order_good.go 5.3 KB
package domain

import (
	"errors"

	"github.com/shopspring/decimal"
)

//分红状态
type OrderGoodBonusStatus interface {
	//状态变更为待支付
	WartPayPartnerBonus(orderGood *OrderGood) error
	//状态变更为已支付
	PayPartnerBonus(orderGood *OrderGood) error
}

//货单的支付状态
const (
	//待支付
	OrderGoodWaitPay int = 1
	//已支付
	OrderGoodHasPay int = 2
)

//OrderGood 订单中的货品
type OrderGood struct {
	//货品id
	Id int64 `json:"id"`
	//所属订单id
	OrderId int64 `json:"orderId"`
	//货品名称 长度可能较长
	GoodName string `json:"goodName"`
	//预计的货品数量
	PlanGoodNumber int `json:"planGoodNumber"`
	//调整后的货品数量
	//业务判定时0是有效值,
	//所以用空串表示无值,转换到数据库中为负值
	UseGoodNumber int `json:"useGoodNumber"`
	//货品单价
	Price float64 `json:"price"`
	//合伙人分红比例
	PartnerBonusPercent float64 `json:"partnerBonusPercent"`
	//分红支付状态
	BonusStatus int `json:"bonusStatus"`
	//备注信息
	Remark string `json:"remark"`
	//当前分红支付状态
	CurrentBonusStatus OrderGoodBonusStatus `json:"-"`
	///核算订单相关数据
	GoodCompute GoodCompute `json:"goodCompute"`
}

type GoodCompute struct {
	//预计的货品总额
	PlanAmount float64 `json:"planAmount"`
	//调整后的货品总额 (初始值=-1)
	//业务判定时0是有效值,
	//所以用空串表示无值,转换到数据库中为负值
	UseAmount float64 `json:"useAmount"`
	//预计的合伙人分红
	PlanPartnerBonus float64 `json:"planPartnerBonus"`
	//合伙人应收分红调整 (初始值=-1),
	//业务判定时0是有效值,
	//所以用空串表示无值,转换到数据库中为负值
	UsePartnerBonus float64 `json:"usePartnerBonus"`
	//合伙人已收分红
	PartnerBonusHas float64 `json:"partnerBonusHas"`
	//合伙人未收分红
	PartnerBonusNot float64 `json:"partnerBonusNot"`
	//合伙人分红支出
	PartnerBonusExpense float64 `json:"partnerBonusExpense"`
}

//OrderGoodBonusWaitPay 货品分红待支付
type OrderGoodBonusWaitPay struct{}

var _ OrderGoodBonusStatus = (*OrderGoodBonusWaitPay)(nil)

//OrderGoodBonusHasPay 货品分红已支付
type OrderGoodBonusHasPay struct{}

var _ OrderGoodBonusStatus = (*OrderGoodBonusHasPay)(nil)

func (waitPay OrderGoodBonusWaitPay) WartPayPartnerBonus(good *OrderGood) error {
	good.GoodCompute.PartnerBonusExpense = 0
	good.GoodCompute.PartnerBonusHas = 0
	//初始状态为待支付时 ,合伙人未收分红等于合伙人应收分红(或者调整的)
	if good.UseGoodNumber < 0 {
		good.GoodCompute.PartnerBonusNot = good.GoodCompute.PlanPartnerBonus
	} else {
		good.GoodCompute.PartnerBonusNot = good.GoodCompute.UsePartnerBonus
	}
	return nil
}

func (waitPay OrderGoodBonusWaitPay) PayPartnerBonus(good *OrderGood) error {
	//待支付状态转支付时 ,合伙人已收收分红等于合伙人应收分红(或者调整的)
	if good.GoodCompute.UsePartnerBonus < 0 {
		good.GoodCompute.PartnerBonusHas = good.GoodCompute.PlanPartnerBonus
	} else {
		good.GoodCompute.PartnerBonusHas = good.GoodCompute.UsePartnerBonus
	}
	good.GoodCompute.PartnerBonusExpense = 0
	good.GoodCompute.PartnerBonusNot = 0
	return nil
}

func (hasPay OrderGoodBonusHasPay) PayPartnerBonus(good *OrderGood) error {
	//已支付的值保持不变
	//未支付的值保持不变
	//计算分红支出
	//分红支出=应收分红(有出现调整,则取调整后的应收分红)和已收分红的差额
	if good.UseGoodNumber >= 0 {
		good.GoodCompute.PartnerBonusExpense = good.GoodCompute.PartnerBonusHas - good.GoodCompute.UsePartnerBonus
	}
	return nil
}

func (hasPay OrderGoodBonusHasPay) WartPayPartnerBonus(good *OrderGood) error {
	return errors.New("已支付的货单不能将状态回退为待支付")
}

//NewOrderGood 初始值设定
func NewOrderGood() OrderGood {
	return OrderGood{
		UseGoodNumber: -1,
		BonusStatus:   OrderGoodWaitPay,
		GoodCompute: GoodCompute{
			UsePartnerBonus: -1,
			UseAmount:       -1,
		},
		CurrentBonusStatus: OrderGoodBonusWaitPay{},
	}
}

//Compute 数据汇总核算
func (good *OrderGood) Compute() error {
	price := decimal.NewFromFloat(good.Price)
	planamount := price.Mul(decimal.NewFromInt(int64(good.PlanGoodNumber))) //price*planGoodNumber
	//price*useGoodNumber
	planPartnerBonus := planamount.Mul(decimal.NewFromFloat(good.PartnerBonusPercent)) //price*planGoodNumber*PartnerBonusPercent

	good.GoodCompute.PlanAmount, _ = planamount.Round(2).Float64()
	good.GoodCompute.PlanPartnerBonus, _ = planPartnerBonus.Round(2).Float64()
	if good.UseGoodNumber < 0 {
		//没有出现数量调整
		good.GoodCompute.UsePartnerBonus = -1
		good.GoodCompute.UseAmount = -1
	} else {
		useamount := price.Mul(decimal.NewFromInt(int64(good.UseGoodNumber)))            //price*useGoodNumber/price*useGoodNumber
		usePartnerBonus := useamount.Mul(decimal.NewFromFloat(good.PartnerBonusPercent)) //price*useGoodNumber*PartnerBonusPercent
		good.GoodCompute.UsePartnerBonus, _ = usePartnerBonus.Round(2).Float64()
		good.GoodCompute.UseAmount, _ = useamount.Round(2).Float64()
	}

	return nil
}

type OrderGoodFindQuery struct {
	OrderId int64
	Offset  int
	Limit   int
}

type OrderGoodRepository interface {
	Save(order []OrderGood) error
	Find(queryOptions OrderGoodFindQuery) ([]OrderGood, int, error)
	Remove(orderid int64, ids ...int64) error
}