Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jm mb 506 part2 zero down migration #3438

Merged
merged 6 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ The test DB commands all talk to the DB over localhost. But in a docker-only en

#### Migrations

To add new regular and/or secure migrations, see the [database development guide](./docs/database.md)
To add new regular and/or secure migrations, see the [database development guide](https://github.com/transcom/mymove/blob/master/docs/database/database.md)
jacquelineIO marked this conversation as resolved.
Show resolved Hide resolved

Running migrations in local development:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE payment_service_items
DROP CONSTRAINT payment_service_items_service_item_id_fkey,
DROP COLUMN service_item_id,
ALTER COLUMN mto_service_item_id SET NOT NULL,
ADD CONSTRAINT payment_service_items_mto_service_item_id_fkey FOREIGN KEY (mto_service_item_id) REFERENCES mto_service_items (id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #3413, we added the new mto_service_item_id column and copied the service_item_id value into that new column for every payment_service_items record. There were no code changes with that PR. So wouldn't the code have still been writing to service_item_id in payment_service_items? And if that's the case, then wouldn't we be losing the service_item_id/mto_service_item_id for any payment_service_items added between PRs when we drop the service_item_id column above? Or am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@reggieriser I think you are right. Should I do that copy again here?
This did cross my mind and I forgot :-/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, none of this is actually live so it's not an issue. But I would like to get it right.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that others may look to this as an example pattern to follow, though. I think the docs state to do it the way you did, too, so we should probably clarify that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated this migration to do the copy again, but wondering if I should do what I'm doing or maybe even only update if mto_service_item_id is NULL like:

UPDATE payment_service_items SET mto_service_item_id = service_item_id
    WHERE mto_service_item_id IS NULL;

instead of what I picked which was:

UPDATE payment_service_items SET mto_service_item_id = service_item_id
    WHERE service_item_id IS NOT NULL;

Copy link
Contributor

@reggieriser reggieriser Feb 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need the where clause at all? In theory, you don't know if the service_item_id has changed between the first PR and this one, so you could lose data if you only update a subset of records (although in practice, that's unlikely right now). Could you just update all the records again since you aren't using mto_service_id in the code until this PR?

Ignore the above in relation to this PR -- I was confused about the ordering of some related PRs. #3401 comes first, then this one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the way you have the UPDATE currently is the right way to do this given the order of the PRs so far.

1 change: 1 addition & 0 deletions migrations_manifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -442,3 +442,4 @@
20200124172904_alter_table_payment_service_items_column_service_item_id.up.sql
20200124192943_update_tariff400ng_mistaken_rate_area.up.sql
20200128024819_fix_rolename_typo.up.sql
20200131173648_remove-service_id-from-payment_service_item.up.sql
12 changes: 8 additions & 4 deletions pkg/handlers/primeapi/payment_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,13 @@ func (h CreatePaymentRequestHandler) Handle(params paymentrequestop.CreatePaymen
MoveTaskOrderID: mtoID,
}

// Build up the paymentRequest.PaymentServiceItems using the incoming payload to offload Swagger data coming
// in from the API. These paymentRequest.PaymentServiceItems will be used as a temp holder to process the incoming API data
paymentRequest.PaymentServiceItems, err = h.buildPaymentServiceItems(payload)
if err != nil {
logger.Error("could not build service items", zap.Error(err))
// TODO: do not bail out before creating the payment request, we need the failed record
// we should create the failed record and store it as failed with a rejection
return paymentrequestop.NewCreatePaymentRequestBadRequest()
}

Expand All @@ -83,14 +87,14 @@ func (h CreatePaymentRequestHandler) buildPaymentServiceItems(payload *primemess
var paymentServiceItems models.PaymentServiceItems

for _, payloadServiceItem := range payload.ServiceItems {
serviceItemID, err := uuid.FromString(payloadServiceItem.ID.String())
mtoServiceItemID, err := uuid.FromString(payloadServiceItem.ID.String())
if err != nil {
return nil, fmt.Errorf("could not convert service item ID [%v] to UUID: %w", payloadServiceItem.ID, err)
}

paymentServiceItem := models.PaymentServiceItem{
// The rest of the model will be filled in when the payment request is created
ServiceItemID: serviceItemID,
MTOServiceItemID: mtoServiceItemID,
}

paymentServiceItem.PaymentServiceItemParams = h.buildPaymentServiceItemParams(payloadServiceItem)
Expand All @@ -101,10 +105,10 @@ func (h CreatePaymentRequestHandler) buildPaymentServiceItems(payload *primemess
return paymentServiceItems, nil
}

func (h CreatePaymentRequestHandler) buildPaymentServiceItemParams(payloadServiceItem *primemessages.ServiceItem) models.PaymentServiceItemParams {
func (h CreatePaymentRequestHandler) buildPaymentServiceItemParams(payloadMTOServiceItem *primemessages.ServiceItem) models.PaymentServiceItemParams {
var paymentServiceItemParams models.PaymentServiceItemParams

for _, payloadServiceItemParam := range payloadServiceItem.Params {
for _, payloadServiceItemParam := range payloadMTOServiceItem.Params {
paymentServiceItemParam := models.PaymentServiceItemParam{
// ID and PaymentServiceItemID to be filled in when payment request is created
IncomingKey: payloadServiceItemParam.Key,
Expand Down
6 changes: 3 additions & 3 deletions pkg/models/payment_service_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var validPaymentServiceItemStatus = []string{
type PaymentServiceItem struct {
ID uuid.UUID `json:"id" db:"id"`
PaymentRequestID uuid.UUID `json:"payment_request_id" db:"payment_request_id"`
ServiceItemID uuid.UUID `json:"service_item_id" db:"service_item_id"`
MTOServiceItemID uuid.UUID `json:"mto_service_item_id" db:"mto_service_item_id"`
Status PaymentServiceItemStatus `json:"status" db:"status"`
PriceCents unit.Cents `json:"price_cents" db:"price_cents"`
RejectionReason *string `json:"rejection_reason" db:"rejection_reason"`
Expand All @@ -50,7 +50,7 @@ type PaymentServiceItem struct {

//Associations
PaymentRequest PaymentRequest `belongs_to:"payment_request"`
ServiceItem MTOServiceItem `belongs_to:"mto_service_item"`
MTOServiceItem MTOServiceItem `belongs_to:"mto_service_item"`
PaymentServiceItemParams PaymentServiceItemParams `has_many:"payment_service_item_params"`
}

Expand All @@ -61,7 +61,7 @@ type PaymentServiceItems []PaymentServiceItem
func (p *PaymentServiceItem) Validate(tx *pop.Connection) (*validate.Errors, error) {
return validate.Validate(
&validators.UUIDIsPresent{Field: p.PaymentRequestID, Name: "PaymentRequestID"},
&validators.UUIDIsPresent{Field: p.ServiceItemID, Name: "ServiceItemID"},
&validators.UUIDIsPresent{Field: p.MTOServiceItemID, Name: "MTOServiceItemID"},
&validators.StringInclusion{Field: p.Status.String(), Name: "Status", List: validPaymentServiceItemStatus},
&validators.TimeIsPresent{Field: p.RequestedAt, Name: "RequestedAt"},
// TODO: Removing this until we have pricing to populate
Expand Down
12 changes: 6 additions & 6 deletions pkg/models/payment_service_item_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func (suite *ModelSuite) TestPaymentServiceItemValidation() {
suite.T().Run("test valid PaymentServiceItem", func(t *testing.T) {
validPaymentServiceItem := models.PaymentServiceItem{
PaymentRequestID: uuid.Must(uuid.NewV4()),
ServiceItemID: uuid.Must(uuid.NewV4()),
MTOServiceItemID: uuid.Must(uuid.NewV4()), //MTO Service Item
Status: "REQUESTED",
RequestedAt: time.Now(),
PriceCents: unit.Cents(1000),
Expand All @@ -28,10 +28,10 @@ func (suite *ModelSuite) TestPaymentServiceItemValidation() {
invalidPaymentServiceItem := models.PaymentServiceItem{}

expErrors := map[string][]string{
"payment_request_id": {"PaymentRequestID can not be blank."},
"service_item_id": {"ServiceItemID can not be blank."},
"status": {"Status is not in the list [REQUESTED, APPROVED, DENIED, SENT_TO_GEX, PAID]."},
"requested_at": {"RequestedAt can not be blank."},
"payment_request_id": {"PaymentRequestID can not be blank."},
"m_t_os_ervice_item_id": {"MTOServiceItemID can not be blank."},
"status": {"Status is not in the list [REQUESTED, APPROVED, DENIED, SENT_TO_GEX, PAID]."},
"requested_at": {"RequestedAt can not be blank."},
// TODO: Removing this until we have pricing to populate
// "price_cents": {"PriceCents can not be blank.", "0 is not greater than 0."},
}
Expand All @@ -42,7 +42,7 @@ func (suite *ModelSuite) TestPaymentServiceItemValidation() {
suite.T().Run("test invalid status for PaymentServiceItem", func(t *testing.T) {
invalidPaymentServiceItem := models.PaymentServiceItem{
PaymentRequestID: uuid.Must(uuid.NewV4()),
ServiceItemID: uuid.Must(uuid.NewV4()),
MTOServiceItemID: uuid.Must(uuid.NewV4()), //MTO Service Item
Status: "Sleeping",
RequestedAt: time.Now(),
PriceCents: unit.Cents(1000),
Expand Down
2 changes: 1 addition & 1 deletion pkg/models/service_param.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type ServiceParam struct {
}

// ServiceParams is not required by pop and may be deleted
type ServiceParams []ServiceParams
type ServiceParams []ServiceParam

// Validate gets run every time you call a "pop.Validate*" (pop.ValidateAndSave, pop.ValidateAndCreate, pop.ValidateAndUpdate) method.
func (p *ServiceParam) Validate(tx *pop.Connection) (*validate.Errors, error) {
Expand Down
7 changes: 7 additions & 0 deletions pkg/payment_request/payment_request_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package paymentrequest

import "github.com/gobuffalo/pop"

type RequestPaymentHelper struct {
DB *pop.Connection
}
25 changes: 25 additions & 0 deletions pkg/payment_request/payment_request_helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package paymentrequest

import (
"testing"

"github.com/stretchr/testify/suite"

"github.com/transcom/mymove/pkg/testingsuite"

"go.uber.org/zap"
)

type PaymentRequestHelperSuite struct {
testingsuite.PopTestSuite
logger *zap.Logger
}

func TestPaymentRequestHelperSuite(t *testing.T) {
ts := &PaymentRequestHelperSuite{
PopTestSuite: testingsuite.NewPopTestSuite(testingsuite.CurrentPackage()),
logger: zap.NewNop(),
}
suite.Run(t, ts)
ts.PopTestSuite.TearDown()
}
26 changes: 26 additions & 0 deletions pkg/payment_request/service_param_list_fetcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package paymentrequest

import (
"fmt"

"github.com/gofrs/uuid"

"github.com/transcom/mymove/pkg/models"
)

func (p *RequestPaymentHelper) FetchServiceParamList(mtoServiceID uuid.UUID) (models.ServiceParams, error) {
mtoServiceItem := models.MTOServiceItem{}
serviceParams := models.ServiceParams{}

err := p.DB.Where("id = ?", mtoServiceID).First(&mtoServiceItem)
if err != nil {
return nil, fmt.Errorf("failure fetching MTO Service Item: %w", err)
}

err = p.DB.Where("service_id = ?", mtoServiceItem.ReServiceID).Eager().All(&serviceParams)
if err != nil {
return nil, fmt.Errorf("failure fetching service params for MTO Service Item ID <%s> with RE Service Item ID <%s>: %w", mtoServiceID.String(), mtoServiceItem.ReServiceID.String(), err)
}

return serviceParams, err
}
30 changes: 30 additions & 0 deletions pkg/payment_request/service_param_list_valid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package paymentrequest

import (
"github.com/transcom/mymove/pkg/models"
)

func (p *RequestPaymentHelper) ValidServiceParamList(mtoServiceItem models.MTOServiceItem, serviceParams models.ServiceParams, paymentServiceItemParams models.PaymentServiceItemParams) (bool, string) {
var errorString string
hasError := false
for _, serviceParam := range serviceParams {
found := false
for _, paymentServiceItemParam := range paymentServiceItemParams {
if serviceParam.ServiceItemParamKey.Key == paymentServiceItemParam.ServiceItemParamKey.Key &&
serviceParam.ServiceID.String() == mtoServiceItem.ReServiceID.String() {
found = true
}
}
if found == false {
hasError = true
errorString = errorString + " Param Key <" + serviceParam.ServiceItemParamKey.Key + ">"
}
}

if hasError {
errorMessage := " MTO Service Item <" + mtoServiceItem.ID.String() + "> missing params needed for pricing: " + errorString
return !hasError, errorMessage
}

return !hasError, ""
}
Loading