package tests

import (
	"fmt"
	"net/http"
	"time"

	"github.com/tidbcloud/account/idl/pbgen/proto/account"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/api"
	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/constant"
	"github.com/pingcap/dbaas/billing2/db"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/handler/centralhandler"
	"github.com/pingcap/dbaas/billing2/handler/paymenthandler"
	"github.com/pingcap/dbaas/billing2/handler/paymenthandler/impl"
	"github.com/pingcap/dbaas/billing2/model/billing"
	"github.com/pingcap/dbaas/billing2/model/billingconfig"
	"github.com/pingcap/dbaas/billing2/model/billingconfig/event_handler"
	"github.com/pingcap/dbaas/billing2/model/costexplorer"
	"github.com/pingcap/dbaas/billing2/model/marketing"
	"github.com/pingcap/dbaas/billing2/model/marketing/discount"
	"github.com/pingcap/dbaas/billing2/model/marketing/plan"
	"github.com/pingcap/dbaas/billing2/model/marketing/unit_filter"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/pingcap/dbaas/billing2/utils/tests/datainit"
	"github.com/pingcap/dbaas/billing2/utils/timeutils"
	"github.com/pingcap/dbaas/billing2/workers"
	"github.com/shopspring/decimal"
)

type MockPartnerCentralHandlerImpl struct {
	MockCentralHandlerImpl
}

const CPPOPaymentCode1 = "ADCXA12345"
const CPPOPaymentCode2 = "ADCXA12346"

func (*MockPartnerCentralHandlerImpl) GetTenant(tenantID uint) (*forms.Tenant, error) {
	switched := !timeutils.GetNow().Before(datainit.BillingDate.AddDate(0, 1, 0))
	switch tenantID {
	case 10:
		// CPPO customer
		return &forms.Tenant{
			TenantID:                  tenantID,
			ThirdPartyAccountProvider: constant.AwsAccountProvider,
			ThirdPartyAccountCode:     CPPOPaymentCode1,
			Status:                    centralhandler.TenantStatusActive,
			IsCPPOCustomer:            switched,
		}, nil
	case 20:
		// CPPO reseller
		return &forms.Tenant{
			TenantID:       tenantID,
			Status:         centralhandler.TenantStatusActive,
			IsCPPOReseller: true,
		}, nil
	case 30:
		// CPPO customer
		code := "22222"
		if switched {
			code = CPPOPaymentCode2
		}
		return &forms.Tenant{
			TenantID:                  tenantID,
			ThirdPartyAccountProvider: constant.AwsAccountProvider,
			ThirdPartyAccountCode:     code,
			Status:                    centralhandler.TenantStatusActive,
			IsCPPOCustomer:            switched,
			ThirdPartyFreeTrial:       !switched,
		}, nil
	case 40:
		// MSP Customer
		return &forms.Tenant{
			TenantID:                  tenantID,
			ThirdPartyAccountProvider: constant.AwsAccountProvider,
			ThirdPartyAccountCode:     "3333",
			Status:                    centralhandler.TenantStatusActive,
			IsMspCustomer:             !switched,
		}, nil
	case 50:
		// MSP
		return &forms.Tenant{
			TenantID: tenantID,
			Status:   centralhandler.TenantStatusActive,
			IsMsp:    true,
		}, nil
	default:
		return &forms.Tenant{
			TenantID: tenantID,
			Status:   centralhandler.TenantStatusActive,
		}, nil
	}
}

func (*MockPartnerCentralHandlerImpl) UpdateAccountThirdPartyInfo(tenantID uint, thirdPartyAccountCode string) error {
	return nil
}

func (*MockPartnerCentralHandlerImpl) GetMspCustomerScheduleInfo(customerID uint) (*forms.MspCustomerScheduleInfo, error) {
	effectedAt := datainit.BillingDate.AddDate(0, 1, 0)
	switch customerID {
	case 40:
		// MSP customer
		return &forms.MspCustomerScheduleInfo{
			MspTenantID:      50,
			CustomerTenantID: uint64(customerID),
			Status:           "",
			EffectedAt:       effectedAt,
			ExpiredAt:        nil,
		}, nil
	default:
		return nil, billing_errors.ObjectNotExistsError
	}
}

func (i *MockPartnerCentralHandlerImpl) GetPendingCustomerScheduleInfo(tenantID uint, partnerType account.PartnerType) ([]*forms.PartnerCustomerScheduleInfo, error) {
	switch partnerType {
	case account.PartnerType_PARTNER_TYPE_MSP:
		result, err := i.GetMspCustomerScheduleInfo(tenantID)
		if err != nil {
			return nil, err
		}
		return []*forms.PartnerCustomerScheduleInfo{
			{PartnerTenantID: result.MspTenantID, CustomerTenantID: result.CustomerTenantID, Status: result.Status, EffectedAt: result.EffectedAt},
		}, nil
	}
	return nil, nil
}

func (suite *PaymentSuite) TestLegacyCPPOPayment() {
	assert := suite.Assert()
	config.Get().Set(config.AWSPaymentEnable, false)
	config.Get().Set(config.AWSDisableHourlyInvoiceSendingAfter, datainit.BillingDate)
	centralhandler.SetCentralHandler(&MockPartnerCentralHandlerImpl{})
	paymenthandler.SetPaymentHandler(&impl.PaymentHandlerImpl{})
	timeutils.SetMockNow(datainit.BillingDate)
	assert.NoError(datainit.CreateCompany())
	assert.NoError((&marketing.SupportPlanModel{}).CreateSupportPlanUnits())
	var customerTenantID uint = 10
	var resellerTenantID uint = 20
	var err error
	_, err = datainit.CreateBillingConfig(customerTenantID, entity.BillingConfigType_DirectCustomer)
	assert.NoError(err)
	_, err = datainit.CreateBillingConfig(resellerTenantID, entity.BillingConfigType_MarketplaceReseller)
	assert.NoError(err)
	//var swicthAccountCustomerTenantID uint = 3
	billingConfigModel := &billingconfig.BillingConfigModel{}
	discountModel := &discount.Model{}
	directBillingConfigID, err := billingConfigModel.GetActiveBillingConfigID(customerTenantID)
	assert.NoError(err)
	p0, err := paymentModel.CreatePaymentMethodAndActive(customerTenantID, &forms.PaymentMethodCreateQuery{
		TenantID:              customerTenantID,
		PaymentType:           entity.PaymentType_AWS,
		PaymentCode:           CPPOPaymentCode1,
		BindedBillingConfigID: &directBillingConfigID,
	})
	assert.NoError(err)
	tenantPlanModel := &plan.TenantPlanModel{}
	err = tenantPlanModel.EnableTenantOnDemandPlan(customerTenantID)
	cppoCreateQuery := forms.CPPOBillingConfig{
		MarketplaceResellerBillingConfig: forms.MarketplaceResellerBillingConfig{
			TenantID:      customerTenantID,
			EffectiveDate: timeutils.GetTimeAddr(datainit.BillingDate.AddDate(0, 1, 0)),
			PaymentCode:   CPPOPaymentCode1,
			ResellerId:    resellerTenantID,
		},
	}
	customerBillingConfigID, paymentBillingConfigID, err := billingConfigModel.CreateMarketplaceResellerBillingConfig(cppoCreateQuery.MarketplaceResellerBillingConfig)
	assert.NoError(err)
	p1, err := paymentModel.CreatePaymentMethodAndActive(customerTenantID, &forms.PaymentMethodCreateQuery{
		TenantID:              customerTenantID,
		PaymentType:           entity.PaymentType_AWSCPPOTransfer,
		PaymentCode:           fmt.Sprint(resellerTenantID),
		BindedBillingConfigID: &customerBillingConfigID,
	})
	assert.NoError(err)
	p2, err := paymentModel.CreatePaymentMethodAndActive(resellerTenantID, &forms.PaymentMethodCreateQuery{
		TenantID:              resellerTenantID,
		PaymentType:           entity.PaymentType_AWS,
		PaymentCode:           cppoCreateQuery.PaymentCode,
		BindedBillingConfigID: &paymentBillingConfigID,
	})
	assert.NoError(err)
	generalUnitFilter, err := (&unit_filter.Model{}).CreateUnitFilter(&forms.UnitFilter{
		UnitFilterSlim: forms.UnitFilterSlim{Name: "General", Description: "General"},
		Region:         forms.UnitFilterALL,
		Provider:       forms.UnitFilterALL,
		Category:       forms.UnitFilterALL,
		UnitKeyPattern: "^(?!support-plan).*$",
		General:        false,
	})
	assert.NoError(err)
	config.Get().Set(config.GeneralCreditTypeID, generalUnitFilter.FilterID)
	normalDiscountVal := decimal.RequireFromString("0.7")
	normalDiscount, err := discountModel.CreateDiscount(customerTenantID, &forms.Discount{
		Value:                 normalDiscountVal,
		StartedAt:             datainit.BillingDate,
		ExpiredAt:             datainit.BillingDate.AddDate(0, 2, 0).Add(-time.Second),
		BindedBillingConfigID: &directBillingConfigID,
		UnitFilters:           []*forms.UnitFilterSlim{{FilterID: generalUnitFilter.FilterID}},
	})
	assert.NoError(err)
	cppoDiscountVal := decimal.RequireFromString("0.5")
	cppoDiscount, err := discountModel.CreateDiscount(resellerTenantID, &forms.Discount{
		Value:                 cppoDiscountVal,
		StartedAt:             datainit.BillingDate.AddDate(0, 1, 0),
		ExpiredAt:             datainit.BillingDate.AddDate(0, 2, 0).Add(-time.Second),
		BindedBillingConfigID: &paymentBillingConfigID,
		UnitFilters:           []*forms.UnitFilterSlim{{FilterID: generalUnitFilter.FilterID}},
		Usage:                 constant.DiscountUsageCPPO,
	})
	assert.NoError(err)
	supportPlanModel := &marketing.SupportPlanModel{}
	info, err := supportPlanModel.CreateSupportPlan(&forms.SupportPlan{
		FixedChargePrice:       decimal.NewFromInt(15),
		SupportPricePercentage: decimal.RequireFromString("0.2"),
		Type:                   entity.SupportPlanType_PercentagePrice,
		Public:                 true,
		Level:                  entity.SupportPlanLevel_Standard,
	})
	assert.NoError(err)
	bindedSupportPlan, err := supportPlanModel.BindSupportPlanForPayableCustomer(customerTenantID, info.SupportPlanID, forms.DateInterval{StartDate: timeutils.GetTimeAddr(datainit.BillingDate)})
	assert.NoError(err)
	fmt.Println(directBillingConfigID, paymentBillingConfigID, p0.PaymentMethodID, p1.PaymentMethodID, p2.PaymentMethodID, bindedSupportPlan.BindedPackageID, cppoDiscount.Value)
	_, err = (&billing.UnitModel{}).CreateUnit(&forms.UnitInfo{
		UnitKey:   datainit.TestUnit,
		Price:     decimal.NewFromInt(1),
		PriceType: entity.PriceType_Normal,
	})
	assert.NoError(err)
	unitCosts := forms.UnitCosts{
		Unit:          datainit.TestUnit,
		CostTimeStamp: timeutils.GetNow().Unix(),
		Cost:          100,
	}
	measureModel := &billing.MeasureModel{}
	res, err := measureModel.CostUnits(customerTenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(directBillingConfigID, res.BindedBillingConfigID)
	assert.Equal(normalDiscount.Value, res.Discount)
	assert.Equal(entity.ConsumedSource_Invoice, res.ConsumedSource)
	assert.False(res.Internal)

	timeutils.SetMockNow(datainit.BillingDate.Add((config.Get().GetDuration(config.MeasureDelayHours)) * time.Hour))
	workers.SupportPlanWorkerByTenant(customerTenantID)

	costexplorerModel := &costexplorer.CostExplorerModel{}
	historyBills, err := costexplorerModel.GetMonthlyCost(customerTenantID, directBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(84), historyBills.TotalCosts.CostPrice)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 1, 0).Add(-5 * time.Minute))
	var customerBillingConfig entity.BillingConfig
	err = entity.NewBillingConfigQuerySet(db.GetDB()).IDEq(customerBillingConfigID).One(&customerBillingConfig)
	assert.NoError(err)
	err = billingConfigModel.SwitchBillingConfig(customerBillingConfig, false)
	assert.NoError(err)
	err = paymentModel.PaymentProcessOnBillingConfigSwitched(customerBillingConfigID)
	assert.NoError(err)
	planModel := &plan.TenantPlanModel{}
	err = planModel.EnableTenantOnDemandPlanByBillingConfigID(customerTenantID, customerBillingConfigID)
	assert.NoError(err)
	var paymentBillingConfig entity.BillingConfig
	err = entity.NewBillingConfigQuerySet(db.GetDB()).IDEq(paymentBillingConfigID).One(&paymentBillingConfig)
	assert.NoError(err)
	err = billingConfigModel.SwitchBillingConfig(paymentBillingConfig, false)
	assert.NoError(err)
	err = paymentModel.PaymentProcessOnBillingConfigSwitched(paymentBillingConfigID)
	assert.NoError(err)
	err = planModel.EnableTenantOnDemandPlanByBillingConfigID(resellerTenantID, paymentBillingConfigID)
	assert.NoError(err)
	payment, err := paymentModel.GetActivePaymentMethod(customerTenantID, customerBillingConfigID)
	assert.NoError(err)
	assert.True(payment.Payable)
	assert.Equal(entity.PaymentType_AWSCPPOTransfer, payment.PaymentType)
	assert.Equal(fmt.Sprintf("%d-%d", resellerTenantID, paymentBillingConfigID), payment.PaymentCode)
	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 1, 0))
	unitCosts.CostTimeStamp = timeutils.GetNow().Unix()
	res, err = measureModel.CostUnits(customerTenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(customerBillingConfigID, res.BindedBillingConfigID)
	assert.Equal(decimal.NewFromInt(1), res.Discount)
	assert.Equal(entity.ConsumedSource_Invoice, res.ConsumedSource)
	assert.False(res.Internal)

	customerBills, err := costexplorerModel.GetMonthlyCost(customerTenantID, customerBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(100), customerBills.TotalCosts.CostPrice)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 1, 1))

	workers.CreateInvoiceWorkerByTenant(customerTenantID)
	var invoices []entity.Invoice
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(customerTenantID).TypeEq(entity.InvoiceType_INMONTH).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	assert.Equal(decimal.NewFromInt(84), invoices[0].CostPrice)
	assert.Equal(entity.InvoiceStatus_SENT, invoices[0].Status)
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(customerTenantID).TypeEq(entity.InvoiceType_HOURLY).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	assert.Equal(entity.InvoiceStatus_SENT, invoices[0].Status)
	assert.Equal(customerBillingConfigID, invoices[0].BindedBillingConfigID)
	assert.Equal(p1.PaymentMethodID, *invoices[0].PaymentMethodID)

	resellerBills, err := costexplorerModel.GetMonthlyCost(resellerTenantID, paymentBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(50), resellerBills.TotalCosts.CostPrice)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 1, 0).Add((config.Get().GetDuration(config.MeasureDelayHours)) * time.Hour))
	workers.SupportPlanWorkerByTenant(customerTenantID)

	historyBills, err = costexplorerModel.GetMonthlyCost(customerTenantID, directBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month())-1)
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(85), historyBills.TotalCosts.CostPrice)

	customerBills, err = costexplorerModel.GetMonthlyCost(customerTenantID, customerBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(120), customerBills.TotalCosts.CostPrice)

	resellerBills, err = costexplorerModel.GetMonthlyCost(resellerTenantID, paymentBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(50), resellerBills.TotalCosts.CostPrice)

	resellerBills, err = costexplorerModel.GetMonthlyCost(resellerTenantID, paymentBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 1, 0).Add((config.Get().GetDuration(config.PartnerSupportPlanHours))*time.Hour + time.Second))
	workers.SupportPlanWorkerByTenant(customerTenantID)
	resellerBills, err = costexplorerModel.GetMonthlyCost(resellerTenantID, paymentBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	// Same per-customer base rationale as TestCPPOPayment. The
	// reseller-side costPrice grows from 50 to 70 because the support
	// fee is now computed from the customer's own usage rather than
	// the partner's discounted aggregate.
	assert.Equal(decimal.NewFromInt(70), resellerBills.TotalCosts.CostPrice)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 1, 0).Add(config.Get().GetDuration(config.Invoicehours) * time.Hour))
	workers.CreateInvoiceWorkerByTenant(customerTenantID)
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(customerTenantID).TypeEq(entity.InvoiceType_MONTHLY).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	assert.Equal(decimal.NewFromInt(1), invoices[0].CostPrice)
	assert.Equal(entity.InvoiceStatus_SENT, invoices[0].Status)
	assert.Equal(directBillingConfigID, invoices[0].BindedBillingConfigID)
	assert.Equal(p0.PaymentMethodID, *invoices[0].PaymentMethodID)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 1, 26))
	workers.CreateInvoiceWorkerByTenant(resellerTenantID)
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(resellerTenantID).TypeEq(entity.InvoiceType_INMONTH).InvoiceDateEq(datainit.BillingDate.AddDate(0, 1, 0)).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	assert.Equal(decimal.NewFromInt(70), invoices[0].CostPrice)
	assert.Equal(entity.InvoiceStatus_SENT, invoices[0].Status)
	assert.Equal(paymentBillingConfigID, invoices[0].BindedBillingConfigID)
	assert.Equal(p2.PaymentMethodID, *invoices[0].PaymentMethodID)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 2, 2))
	unitCosts.CostTimeStamp = datainit.BillingDate.AddDate(0, 2, 0).Add(-time.Second).Unix()
	unitCosts.Cost = 10
	res, err = measureModel.CostUnits(customerTenantID, &unitCosts)
	assert.NoError(err)
	workers.SupportPlanWorkerByTenant(customerTenantID)
	customerBills, err = costexplorerModel.GetMonthlyCost(customerTenantID, customerBillingConfigID, 2021, 12)
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(132), customerBills.TotalCosts.CostPrice)
	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 2, 0).Add((config.Get().GetDuration(config.Invoicehours) + 1) * time.Hour))
	workers.CreateInvoiceWorkerByTenant(customerTenantID)
	resellerBills, err = costexplorerModel.GetMonthlyCost(resellerTenantID, paymentBillingConfigID, 2021, 12)
	assert.NoError(err)
	// Per-customer base: the +10 delta vs the legacy value comes from
	// the support fee now computing off the customer's own usage
	// instead of the partner's discounted aggregate.
	assert.Equal(decimal.NewFromInt(75), resellerBills.TotalCosts.CostPrice)
	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 2, 0).Add((config.Get().GetDuration(config.Invoicehours) + 5) * time.Hour))
	workers.SupportPlanWorkerByTenant(customerTenantID)
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(customerTenantID).TypeEq(entity.InvoiceType_MONTHLY).InvoiceDateEq(datainit.BillingDate.AddDate(0, 1, 0)).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)

	resellerBills, err = costexplorerModel.GetMonthlyCost(resellerTenantID, paymentBillingConfigID, 2021, 12)
	assert.NoError(err)
	// Per-customer base: support fee now reflects the customer's own
	// usage instead of the partner's discounted aggregate, raising
	// the reseller-side total from 70.5 to 77.
	assert.Equal(decimal.RequireFromString("77"), resellerBills.TotalCosts.CostPrice)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 2, 0).Add((config.Get().GetDuration(config.Invoicehours) + config.Get().GetDuration(config.PartnerTenantInvoicehours) + 1) * time.Hour))

	workers.CreateInvoiceWorkerByTenant(resellerTenantID)

	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(resellerTenantID).TypeEq(entity.InvoiceType_MONTHLY).InvoiceDateEq(datainit.BillingDate.AddDate(0, 1, 0)).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	// Per-customer base: support fee invoice drops from 10.5 to 7
	// because the calculation now reads the customer's own usage
	// instead of the partner's discounted aggregate.
	assert.Equal(decimal.RequireFromString("7"), invoices[0].CostPrice)
	assert.Equal(entity.InvoiceStatus_SENT, invoices[0].Status)
	assert.Equal(paymentBillingConfigID, invoices[0].BindedBillingConfigID)
	assert.Equal(p2.PaymentMethodID, *invoices[0].PaymentMethodID)
}

func (suite *PaymentSuite) TestCPPOPayment() {
	assert := suite.Assert()
	config.Get().Set(config.AWSPaymentEnable, false)
	config.Get().Set(config.AWSDisableHourlyInvoiceSendingAfter, datainit.BillingDate)
	centralhandler.SetCentralHandler(&MockPartnerCentralHandlerImpl{})
	paymenthandler.SetPaymentHandler(&impl.PaymentHandlerImpl{})
	timeutils.SetMockNow(datainit.BillingDate)
	assert.NoError(datainit.CreateCompany())
	assert.NoError((&marketing.SupportPlanModel{}).CreateSupportPlanUnits())
	var err error
	customerTenantID := uint(10)
	resellerTenantID := uint(20)
	billingConfigModel := &billingconfig.BillingConfigModel{}
	_, err = billingConfigModel.CreateBillingConfigAndActive(forms.BillingConfig{TenantID: customerTenantID, Type: entity.BillingConfigType_DirectCustomer})
	assert.NoError(err)
	customerDirectBillingConfigID, err := billingConfigModel.GetActiveBillingConfigID(customerTenantID)
	assert.NoError(err)
	_, err = billingConfigModel.CreateBillingConfigAndActive(forms.BillingConfig{TenantID: resellerTenantID, Type: entity.BillingConfigType_DirectCustomer})
	assert.NoError(err)
	timeutils.SetMockNow(datainit.BillingDate)
	paymenthandler.SetPaymentHandler(&impl.PaymentHandlerImpl{})
	_, err = paymentModel.CreatePaymentMethodAndActive(customerTenantID, &forms.PaymentMethodCreateQuery{
		TenantID:              customerTenantID,
		PaymentType:           entity.PaymentType_WireTransfer,
		BindedBillingConfigID: &customerDirectBillingConfigID,
	})
	assert.NoError(err)
	tenantPlanModel := &plan.TenantPlanModel{}
	err = tenantPlanModel.EnableTenantOnDemandPlan(customerTenantID)
	assert.NoError(err)

	generalUnitFilter, err := (&unit_filter.Model{}).CreateUnitFilter(&forms.UnitFilter{
		UnitFilterSlim: forms.UnitFilterSlim{Name: "General", Description: "General"},
		Region:         forms.UnitFilterALL,
		Provider:       forms.UnitFilterALL,
		Category:       forms.UnitFilterALL,
		UnitKeyPattern: "^(?!support-plan).*$",
		General:        false,
	})

	assert.NoError(err)
	networkUnitFilter, err := (&unit_filter.Model{}).CreateUnitFilter(&forms.UnitFilter{
		UnitFilterSlim: forms.UnitFilterSlim{Name: "Network", Description: "Network"},
		General:        false,
		UnitKeyPattern: "network",
	})
	assert.NoError(err)
	config.Get().Set(config.GeneralCreditTypeID, generalUnitFilter.FilterID)
	config.Get().Set(config.AWSCPPODiscountedProductUnitFilterIDs, []string{fmt.Sprint(generalUnitFilter.FilterID)})
	tests.MockCentralHandler()
	startedAt := datainit.BillingDate.AddDate(0, 0, 12)
	expiredAt := startedAt.AddDate(1, 0, 0)
	dis := forms.Discount{
		Value:       decimal.RequireFromString("0.5"),
		ExpiredAt:   expiredAt,
		Usage:       constant.DiscountUsageCPPO,
		UnitFilters: []*forms.UnitFilterSlim{{FilterID: generalUnitFilter.FilterID}},
	}
	networkDis := forms.Discount{
		Value:       decimal.RequireFromString("0.9"),
		ExpiredAt:   expiredAt,
		UnitFilters: []*forms.UnitFilterSlim{{FilterID: networkUnitFilter.FilterID}},
	}
	code := "!23"
	support := &forms.SupportPlanInput{
		SupportPlan: forms.SupportPlan{
			Public:                 false,
			Level:                  entity.SupportPlanLevel_Standard,
			Type:                   entity.SupportPlanType_PercentagePrice,
			FixedChargePrice:       decimal.NewFromInt(10),
			SupportPricePercentage: decimal.RequireFromString("0.20"),
		},
		ExpiredDate: &expiredAt,
	}
	router := gin.New()
	router.Use(ginutils.ErrorMiddleWare)
	api.InitializeBillingConfigRouter(ginutils.MyRoute{Route: router})
	cppoCreateQuery := &forms.CPPOBillingConfig{
		MarketplaceResellerBillingConfig: forms.MarketplaceResellerBillingConfig{
			TenantID:        customerTenantID,
			ResellerId:      resellerTenantID,
			EffectiveDate:   &startedAt,
			PaymentCode:     code,
			Discounts:       []forms.Discount{dis, networkDis},
			SupportPlanInfo: support,
		},
	}
	w := tests.PerformRequest(router, "POST", fmt.Sprintf("/tenants/%d/cppo_billing_config", customerTenantID), cppoCreateQuery)
	assert.Equal(http.StatusOK, w.Code)
	timeutils.SetMockNow(*cppoCreateQuery.EffectiveDate)
	workers.BillingConfigScheduledExecution()
	customerBillingConfigID, err := billingConfigModel.GetActiveBillingConfigID(customerTenantID)
	assert.NoError(err)
	supportPlanModel := &marketing.SupportPlanModel{}
	err = supportPlanModel.SupportPlanProcessOnBillingConfigSwitched(customerBillingConfigID)
	assert.NoError(err)
	paymentBillingConfigID, err := billingConfigModel.GetBillingConfigIDByManagedTenantID(customerTenantID)
	err = supportPlanModel.SupportPlanProcessOnBillingConfigSwitched(paymentBillingConfigID)
	assert.NoError(err)
	err = tenantPlanModel.EnableTenantOnDemandPlan(customerTenantID)
	assert.NoError(err)

	err = paymentModel.PaymentProcessOnBillingConfigSwitched(customerBillingConfigID)
	assert.NoError(err)
	err = tenantPlanModel.EnableTenantOnDemandPlanByBillingConfigID(customerTenantID, customerBillingConfigID)
	assert.NoError(err)

	err = paymentModel.PaymentProcessOnBillingConfigSwitched(paymentBillingConfigID)
	assert.NoError(err)
	err = tenantPlanModel.EnableTenantOnDemandPlanByBillingConfigID(resellerTenantID, paymentBillingConfigID)
	assert.NoError(err)
	payment, err := paymentModel.GetActivePaymentMethod(customerTenantID, customerBillingConfigID)
	assert.NoError(err)
	assert.True(payment.Payable)
	assert.Equal(entity.PaymentType_AWSCPPOTransfer, payment.PaymentType)
	assert.Equal(fmt.Sprintf("%d-%d", resellerTenantID, paymentBillingConfigID), payment.PaymentCode)

	_, err = (&billing.UnitModel{}).CreateUnit(&forms.UnitInfo{
		UnitKey:   datainit.TestUnit,
		Price:     decimal.NewFromInt(1),
		PriceType: entity.PriceType_Normal,
	})
	assert.NoError(err)
	unitCosts := forms.UnitCosts{
		Unit:          datainit.TestUnit,
		CostTimeStamp: timeutils.GetNow().Unix(),
		Cost:          100,
	}
	costexplorerModel := &costexplorer.CostExplorerModel{}
	measureModel := &billing.MeasureModel{}
	unitCosts.CostTimeStamp = cppoCreateQuery.EffectiveDate.Add(-100 * time.Second).Unix()
	res, err := measureModel.CostUnits(customerTenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(customerDirectBillingConfigID, res.BindedBillingConfigID)
	assert.Equal(decimal.NewFromInt(1), res.Discount)
	assert.Equal(entity.ConsumedSource_Invoice, res.ConsumedSource)
	assert.False(res.Internal)

	historyBills, err := costexplorerModel.GetMonthlyCost(customerTenantID, customerDirectBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(100), historyBills.TotalCosts.CostPrice)
	customerBills, err := costexplorerModel.GetMonthlyCost(customerTenantID, customerBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(0), customerBills.TotalCosts.CostPrice)

	unitCosts.CostTimeStamp = cppoCreateQuery.EffectiveDate.Unix()
	res, err = measureModel.CostUnits(customerTenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(customerBillingConfigID, res.BindedBillingConfigID)
	assert.Equal(decimal.NewFromInt(1), res.Discount)
	assert.Equal(entity.ConsumedSource_Invoice, res.ConsumedSource)
	assert.False(res.Internal)

	customerBills, err = costexplorerModel.GetMonthlyCost(customerTenantID, customerBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(100), customerBills.TotalCosts.CostPrice)
	timeutils.SetMockNow(cppoCreateQuery.EffectiveDate.Add((config.Get().GetDuration(config.MeasureDelayHours)) * time.Hour))
	workers.CreateInvoiceWorkerByTenant(customerTenantID)
	workers.SupportPlanWorkerByTenant(customerTenantID)
	var invoices []entity.Invoice
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(customerTenantID).TypeEq(entity.InvoiceType_HOURLY).BindedBillingConfigIDEq(customerBillingConfigID).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	assert.Equal(entity.InvoiceStatus_SENT, invoices[0].Status)
	assert.Equal(decimal.NewFromInt(100), invoices[0].CostPrice)

	resellerBills, err := costexplorerModel.GetMonthlyCost(resellerTenantID, paymentBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(50), resellerBills.TotalCosts.CostPrice)

	timeutils.SetMockNow(cppoCreateQuery.EffectiveDate.Add(config.Get().GetDuration(config.Invoicehours)*time.Hour + time.Second))
	workers.CreateInvoiceWorkerByTenant(customerTenantID)
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(customerTenantID).BindedBillingConfigIDEq(customerDirectBillingConfigID).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	assert.Equal(decimal.NewFromInt(100), invoices[0].CostPrice)

	timeutils.SetMockNow(cppoCreateQuery.EffectiveDate.Add((config.Get().GetDuration(config.PartnerSupportPlanHours))*time.Hour + time.Second))
	workers.SupportPlanWorkerByTenant(customerTenantID)
	resellerBills, err = costexplorerModel.GetMonthlyCost(resellerTenantID, paymentBillingConfigID, timeutils.GetNow().Year(), int(timeutils.GetNow().Month()))
	assert.NoError(err)
	// Support fee now bases on the customer's own usage (test_unit
	// costPrice=100 -> 100 * 1000 * 0.2 * 0.001 = 20) plus the CPPO
	// transfer of 50 -> 70 total. The pre-refactor value 60 used the
	// reseller-side discounted costPrice (50 -> 10000 * 0.2 * 0.001 =
	// 10 -> 50+10 = 60), which incorrectly tied support fee to the
	// partner discount.
	assert.Equal(decimal.NewFromInt(70), resellerBills.TotalCosts.CostPrice)

	resellerPayment, err := paymentModel.GetActivePaymentMethod(resellerTenantID, paymentBillingConfigID)
	assert.NoError(err)
	assert.False(resellerPayment.Invoiceable)

	timeutils.SetMockNow(timeutils.GetMonthDate(cppoCreateQuery.EffectiveDate.AddDate(0, 1, 0)).Add(config.Get().GetDuration(config.Invoicehours)*time.Hour + time.Second))
	workers.CreateInvoiceWorkerByTenant(resellerTenantID)
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(resellerTenantID).TypeIn(entity.InvoiceType_MONTHLY, entity.InvoiceType_INMONTH).BindedBillingConfigIDEq(paymentBillingConfigID).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	// Per-customer base: reseller invoice now aggregates the CPPO
	// transfer (50) and the support fee (20 = 100 * 0.2 * 0.001 * 1000
	// milli-units from the customer's own usage), totalling 70.
	assert.Equal(decimal.NewFromInt(70), invoices[0].CostPrice)
	assert.Equal(entity.InvoiceStatus_CONFIRMED, invoices[0].Status)
	config.Get().Set(config.AWSCPPODiscountedProductCode, "5432")
	config.Get().Set(config.AWSCPPONonDiscountedProductCode, "2233422334")
	primaryCode := fmt.Sprintf("%s-%s", config.Get().GetString(config.AWSCPPODiscountedProductCode), "1111")
	secondaryCode := fmt.Sprintf("%s-%s", config.Get().GetString(config.AWSCPPONonDiscountedProductCode), "233234")
	_, err = paymentModel.UpdatePaymentCode(resellerTenantID, resellerPayment.PaymentMethodID, primaryCode, &secondaryCode)
	assert.NoError(err)
	resellerPayment, err = paymentModel.UpdatePaymentInvoiceable(resellerPayment.PaymentMethodID)
	assert.NoError(err)
	assert.True(resellerPayment.Invoiceable)
	assert.Equal(timeutils.GetNow(), *resellerPayment.InvoiceableAt)

	invoiceable, err := paymentModel.BillingConfigInvoiceable(resellerTenantID, paymentBillingConfigID)
	assert.NoError(err)
	assert.False(invoiceable)

	workers.CreateInvoiceWorkerByTenant(resellerTenantID)
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(resellerTenantID).TypeIn(entity.InvoiceType_MONTHLY, entity.InvoiceType_INMONTH).BindedBillingConfigIDEq(paymentBillingConfigID).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	assert.Equal(decimal.NewFromInt(70), invoices[0].CostPrice)
	assert.Equal(entity.InvoiceStatus_CONFIRMED, invoices[0].Status)

	timeutils.SetMockNow(timeutils.GetNow().Add(time.Hour*config.Get().GetDuration(config.InvoicePayableDurationAfterInvoiceableHour) + time.Second))
	invoiceable, err = paymentModel.BillingConfigInvoiceable(resellerTenantID, paymentBillingConfigID)
	assert.NoError(err)
	assert.True(invoiceable)

	workers.CreateInvoiceWorkerByTenant(resellerTenantID)
	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(resellerTenantID).StatusEq(entity.InvoiceStatus_SPLIT).BindedBillingConfigIDEq(paymentBillingConfigID).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	assert.Equal(entity.PaymentType_AWSCPPOReseller, *invoices[0].PaymentType)
	assert.Equal(decimal.NewFromInt(70), invoices[0].CostPrice)

	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(resellerTenantID).BindedBillingConfigIDEq(paymentBillingConfigID).StatusEq(entity.InvoiceStatus_CONFIRMED).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 2)

	workers.CreateInvoiceWorkerByTenant(resellerTenantID)

	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(resellerTenantID).StatusEq(entity.InvoiceStatus_SENT).PaymentCodeEq(primaryCode).BindedBillingConfigIDEq(paymentBillingConfigID).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	assert.Equal(decimal.NewFromInt(50), invoices[0].CostPrice)
	assert.Equal(entity.PaymentType_AWSCPPOReseller, *invoices[0].PaymentType)
	assert.Equal(primaryCode, *invoices[0].PaymentCode)

	err = entity.NewInvoiceQuerySet(db.GetDB()).TenantIDEq(resellerTenantID).StatusEq(entity.InvoiceStatus_SENT).PaymentCodeEq(secondaryCode).BindedBillingConfigIDEq(paymentBillingConfigID).All(&invoices)
	assert.NoError(err)
	assert.Len(invoices, 1)
	// Support fee secondary invoice now carries 20 (the per-customer
	// support fee costPrice) instead of 10 (which used the partner's
	// discounted aggregate). Primary code still holds the 50 CPPO
	// transfer; 50 + 20 = 70 totals the new reseller invoice.
	assert.Equal(decimal.NewFromInt(20), invoices[0].CostPrice)
	assert.Equal(entity.PaymentType_AWSCPPOReseller, *invoices[0].PaymentType)
	assert.Equal(secondaryCode, *invoices[0].PaymentCode)

	commitmentInvoice, err := invoiceModel.CreateCommitmentInvoice(resellerTenantID, &forms.CommitmentInvoiceInput{
		Amount:                decimal.NewFromInt(200),
		Date:                  timeutils.GetNow(),
		Owner:                 "2",
		BindedBillingConfigID: &paymentBillingConfigID,
		PaymentCode:           &secondaryCode,
	})
	assert.NoError(err)
	_, err = invoiceModel.ConfirmInvoice(commitmentInvoice.InvoiceID)
	assert.NoError(err)
	workers.CreateInvoiceWorkerByTenant(resellerTenantID)
	commitmentInvoice, err = invoiceModel.GetInvoice(commitmentInvoice.InvoiceID)
	assert.NoError(err)
	assert.Equal(entity.InvoiceStatus_CONFIRMED, commitmentInvoice.Status)
	timeutils.SetMockNow(timeutils.GetNow().Add(time.Hour + time.Second))
	_, err = invoiceModel.ConfirmInvoice(commitmentInvoice.InvoiceID)
	assert.NoError(err)
	workers.CreateInvoiceWorkerByTenant(resellerTenantID)
	commitmentInvoice, err = invoiceModel.GetInvoice(commitmentInvoice.InvoiceID)
	assert.NoError(err)
	assert.Equal(entity.InvoiceStatus_SENT, commitmentInvoice.Status)
	assert.Equal(secondaryCode, *commitmentInvoice.PaymentCode)
}

func (suite *PaymentSuite) TestMSPPayment() {
	assert := suite.Assert()
	centralhandler.SetCentralHandler(&MockPartnerCentralHandlerImpl{})
	paymenthandler.SetPaymentHandler(&impl.PaymentHandlerImpl{})
	timeutils.SetMockNow(datainit.BillingDate)
	assert.NoError(datainit.CreateCompany())
	assert.NoError((&marketing.SupportPlanModel{}).CreateSupportPlanUnits())
	var customerTenantID uint = 40
	var resellerTenantID uint = 50
	var err error
	_, err = datainit.CreateBillingConfig(customerTenantID, entity.BillingConfigType_DirectCustomer)
	assert.NoError(err)
	_, err = datainit.CreateBillingConfig(resellerTenantID, entity.BillingConfigType_DirectCustomer)
	assert.NoError(err)
	billingConfigModel := &billingconfig.BillingConfigModel{}
	err = (&event_handler.BillingConfigEventHandler{}).CreateOrUpdateBillingConfig(&forms.OrgEventData{
		OrgId:        uint64(customerTenantID),
		OrgEventType: constant.TenantEventTypeSchedule,
	})
	assert.NoError(err)
	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 1, 0).Add(-5 * time.Minute))
	workers.BillingConfigScheduledExecution()
	bcfg, err := billingConfigModel.GetActiveBillingConfig(customerTenantID)
	assert.NoError(err)
	assert.Equal(entity.BillingConfigType_MSPCustomer, bcfg.Type)
	err = paymentModel.PaymentProcessOnBillingConfigSwitched(bcfg.BillingConfigID)
	assert.NoError(err)
	payment, err := paymentModel.GetActivePaymentMethod(customerTenantID, bcfg.BillingConfigID)
	assert.NoError(err)
	assert.True(payment.Payable)
	assert.Equal(entity.PaymentType_MSP, payment.PaymentType)
	assert.Equal(fmt.Sprint(resellerTenantID), payment.PaymentCode)

	// TestPaySkipsSupportFeeForPartnerManagedCustomer is the regression
	// test for MspHandlerImpl.Pay's defensive skip on the four support
	// SKUs. The skip is shared with ResaleCustomer via
	// ResaleHandlerImpl (which embeds MspHandlerImpl), so covering it
	// here exercises both code paths.
	//
	// Setup: an MSPCustomer invoice that contains three cost rows:
	//   1. Regular usage  (test_unit,  Invoice)         — should transfer
	//   2. Support fee    (PercentagePrice_SKU, Invoice) — should skip
	//   3. Credits        (test_unit,  Credits)         — should skip
	//
	// The Pay loop must transfer (1) to the partner's user_unit_costs
	// and leave (2) and (3) off the partner's books.
	const testInvoiceID = 99001
	invoiceDate := datainit.BillingDate.AddDate(0, 0, 5)
	customerBC, err := billingConfigModel.GetBillingConfig(bcfg.BillingConfigID)
	assert.NoError(err)
	resellerBC, err := billingConfigModel.GetActiveBillingConfig(resellerTenantID)
	assert.NoError(err)

	// SecondaryMeasure calls UnitModel.GetUnit, so the unit must
	// exist in the units table for the regular-usage row to transfer.
	_, err = (&billing.UnitModel{}).CreateUnit(&forms.UnitInfo{
		UnitKey:   datainit.TestUnit,
		Price:     decimal.NewFromInt(1),
		PriceType: entity.PriceType_Normal,
	})
	assert.NoError(err)
	costTimeStamp := invoiceDate.Add(time.Hour * 2).Unix()
	regularCost := &entity.UserUnitCost{
		CostID:                "test-pay-skip-regular",
		TenantID:              customerTenantID,
		CostTimeStamp:         costTimeStamp,
		Unit:                  datainit.TestUnit,
		Cost:                  200,
		CostPrice:             decimal.NewFromInt(200),
		Status:                entity.UserUnitCostStatus_DONE,
		BindedBillingConfigID: customerBC.BillingConfigID,
		InvoiceID:             testInvoiceID,
		ConsumedSource:        entity.ConsumedSource_Invoice,
	}
	assert.NoError(regularCost.Create(db.GetDB()))
	supportCost := &entity.UserUnitCost{
		CostID:                "test-pay-skip-support",
		TenantID:              customerTenantID,
		CostTimeStamp:         costTimeStamp,
		Unit:                  constant.PercentagePrice_SKU,
		Cost:                  100,
		CostPrice:             decimal.NewFromInt(100),
		Status:                entity.UserUnitCostStatus_DONE,
		BindedBillingConfigID: customerBC.BillingConfigID,
		InvoiceID:             testInvoiceID,
		ConsumedSource:        entity.ConsumedSource_Invoice,
	}
	assert.NoError(supportCost.Create(db.GetDB()))
	creditsCost := &entity.UserUnitCost{
		CostID:                "test-pay-skip-credits",
		TenantID:              customerTenantID,
		CostTimeStamp:         costTimeStamp,
		Unit:                  datainit.TestUnit,
		Cost:                  50,
		CostPrice:             decimal.NewFromInt(50),
		Status:                entity.UserUnitCostStatus_DONE,
		BindedBillingConfigID: customerBC.BillingConfigID,
		InvoiceID:             testInvoiceID,
		ConsumedSource:        entity.ConsumedSource_Credits,
	}
	assert.NoError(creditsCost.Create(db.GetDB()))

	invoiceEntity := &entity.Invoice{
		TenantID:              customerTenantID,
		Status:                entity.InvoiceStatus_SENT,
		Type:                  entity.InvoiceType_MONTHLY,
		InvoiceDate:           invoiceDate,
		BindedBillingConfigID: customerBC.BillingConfigID,
		CostPrice:             decimal.NewFromInt(350),
		RawPrice:              decimal.NewFromInt(350),
	}
	invoiceEntity.ID = testInvoiceID
	assert.NoError(db.GetDB().Create(invoiceEntity).Error)

	paymentInfo := payment
	formInvoice := &forms.Invoice{
		InvoiceID: testInvoiceID,
		TenantID:  customerTenantID,
		Status:    entity.InvoiceStatus_SENT,
		Type:      entity.InvoiceType_MONTHLY,
		StartDate: invoiceDate,
		EndDate:   invoiceDate,
	}
	_, err = (&impl.MspHandlerImpl{}).Pay(paymentInfo, nil, formInvoice)
	assert.NoError(err)

	// Partner's user_unit_costs filtered by InvoiceID — only the
	// regular usage row should appear. The transfer row is written
	// via SecondaryMeasure which merges into user_unit_costs; the
	// merged row carries the source unit (test_unit) but loses the
	// InvoiceID/ConsumedSource from the customer's invoice row.
	var partnerCosts []entity.UserUnitCost
	err = entity.NewUserUnitCostQuerySet(db.GetDB()).
		TenantIDEq(resellerTenantID).
		BindedBillingConfigIDEq(resellerBC.BillingConfigID).
		All(&partnerCosts)
	assert.NoError(err)
	// Assert: only the regular usage unit (test_unit) transferred.
	// Critically, none of the 4 support SKUs transferred.
	supportSkus := []string{
		constant.FixedPrice_SKU,
		constant.PercentagePrice_SKU,
		constant.TieredPrice_SKU,
		constant.CommintmentPrice_SKU,
	}
	for _, row := range partnerCosts {
		for _, sku := range supportSkus {
			assert.NotEqual(sku, row.Unit, "support SKU %s must not transfer to partner; row=%+v", sku, row)
		}
	}
	// Assert: the regular test_unit row did transfer.
	var testUnitRows []entity.UserUnitCost
	err = entity.NewUserUnitCostQuerySet(db.GetDB()).
		TenantIDEq(resellerTenantID).
		BindedBillingConfigIDEq(resellerBC.BillingConfigID).
		UnitEq(datainit.TestUnit).
		All(&testUnitRows)
	assert.NoError(err)
	assert.Len(testUnitRows, 1, "expected the regular usage row to transfer; got %d rows", len(testUnitRows))
	assert.Equal(200, testUnitRows[0].Cost)

	// Customer's invoice still has all three rows (Pay never deletes
	// from the customer side; it only writes to the partner side).
	var customerCosts []entity.UserUnitCost
	err = entity.NewUserUnitCostQuerySet(db.GetDB()).
		TenantIDEq(customerTenantID).
		InvoiceIDEq(testInvoiceID).
		All(&customerCosts)
	assert.NoError(err)
	assert.Len(customerCosts, 3)
}
