order_good.go 11.4 KB
package domain

import (
	"errors"
	"fmt"

	"github.com/shopspring/decimal"
)

//分红状态
type OrderGoodBonusStatus interface {
	//状态变更为待支付
	WartPayPartnerBonus(orderGood *OrderGood) error
	//状态变更为已支付
	PayPartnerBonus(orderGood *OrderGood) error
	//变更货品数量
	ModifyOrderGoodNumber(good *OrderGood, number int, orderType int) error
	//变更合伙人分红比例
	ModifyPertnerBonusPercent(good *OrderGood, percent float64, orderType int) error
}

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

//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"`
}

type OrderGoodRemarkReason struct {
	ModifyGoodNumber          string `json:"modifyGoodNumber"`          //货品数量变更的理由
	ModifyPartnerBonusPercent string `json:"modifyPartnerBonusPercent"` //合伙人分红比例变更的理由
}

//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"`
	//公司
	CompanyId int64 `json:"companyId"`
	//原因备注
	RemarkReason OrderGoodRemarkReason `json:"remarkReason"`
	DataFrom     OrderDataFrom         `json:"data_from"`
}

//GetCurrentGoodNumber 获取当前的商品数量
func (good OrderGood) GetCurrentGoodNumber() int {
	if good.UseGoodNumber >= 0 {
		return good.UseGoodNumber
	}
	return good.PlanGoodNumber
}

//GetCurrentAmount 获取当前的商品总额
func (good OrderGood) GetCurrentAmount() float64 {
	if good.GoodCompute.UseAmount >= 0 {
		return good.GoodCompute.UseAmount
	}
	return good.GoodCompute.PlanAmount
}

//GetCurrentAmount 获取当前的商品合伙人分红
func (good OrderGood) GetCurrentPartnerBonus() float64 {
	if good.GoodCompute.UsePartnerBonus >= 0 {
		return good.GoodCompute.UsePartnerBonus
	}
	return good.GoodCompute.PlanPartnerBonus
}

//GetCurrentAmount 获取当前的商品合伙人分红
func (good *OrderGood) ModifyOrderGoodNumber(number int, orderType int) error {
	if good.PlanGoodNumber < number {
		return fmt.Errorf("修改数量不能大于初始值:%d", good.PlanGoodNumber)
	}
	err := good.CurrentBonusStatus.ModifyOrderGoodNumber(good, number, orderType)
	return err
}

func (good *OrderGood) ModifyPertnerBonusPercent(percent float64, orderType int) error {
	err := good.CurrentBonusStatus.ModifyPertnerBonusPercent(good, percent, orderType)
	return err
}

//Update 更新商品相关的数据
func (good *OrderGood) Update(m map[string]interface{}) error {
	if v, ok := m["GoodName"]; ok {
		good.GoodName = v.(string)
	}
	if v, ok := m["PlanGoodNumber"]; ok {
		good.PlanGoodNumber = v.(int)
	}
	if v, ok := m["UseGoodNumber"]; ok {
		good.UseGoodNumber = v.(int)
	}
	if v, ok := m["Price"]; ok {
		good.Price = v.(float64)
	}
	if v, ok := m["PartnerBonusPercent"]; ok {
		good.PartnerBonusPercent = v.(float64)
	}
	if v, ok := m["Remark"]; ok {
		good.Remark = v.(string)
	}
	if v, ok := m["RemarkReason"]; ok {
		good.RemarkReason = v.(OrderGoodRemarkReason)
	}
	err := good.Compute()
	return err
}

//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
	}
	good.CurrentBonusStatus = OrderGoodBonusWaitPay{}
	good.BonusStatus = OrderGoodWaitPay
	return nil
}

func (waitPay OrderGoodBonusWaitPay) PayPartnerBonus(good *OrderGood) error {
	//待支付状态转支付时
	//合伙人已收收分红等于合伙人应收分红(或者调整的)
	//计算已支付
	if good.UseGoodNumber < 0 {
		//数量没有调整,已收等于预计应收分红
		good.GoodCompute.PartnerBonusHas = good.GoodCompute.PlanPartnerBonus
	} else {
		//数量有调整,已收等于调整后的应收分红
		good.GoodCompute.PartnerBonusHas = good.GoodCompute.UsePartnerBonus
	}
	good.GoodCompute.PartnerBonusExpense = 0
	good.GoodCompute.PartnerBonusNot = 0
	good.CurrentBonusStatus = OrderGoodBonusHasPay{}
	good.BonusStatus = OrderGoodHasPay
	return nil
}

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

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

func (hasPay OrderGoodBonusHasPay) ModifyOrderGoodNumber(good *OrderGood, number int, orderType int) error {
	//规则描述:
	//实际自建订单(orderType==1),已支付分红状态下“可以”修改货品数量
	//香米小程序订单(orderType==3),已支付分红状态下“不可以”修改货品数量
	switch orderType {
	case OrderReal:
		good.UseGoodNumber = number
		//待支付状态计算
		err := good.Compute()
		if err != nil {
			return errors.New("核算商品数据失败" + err.Error())
		}
	case OrderTypeBestShop:
		return errors.New("小程序订单里已支付分红的货品订单,不能修改货品数量")
	}
	good.CurrentBonusStatus.PayPartnerBonus(good)
	return nil
}

func (waitPay OrderGoodBonusWaitPay) ModifyOrderGoodNumber(good *OrderGood, number int, orderType int) error {
	//规则描述:
	//实际自建订单(orderType==1),未支付分红状态下“可以”修改货品数量
	//香米小程序订单(orderType==3),未支付分红状态下“可以”修改货品数量
	good.UseGoodNumber = number
	//待支付状态计算
	err := good.Compute()
	if err != nil {
		return errors.New("核算商品数据失败" + err.Error())
	}
	good.CurrentBonusStatus.WartPayPartnerBonus(good)
	return nil
}

func (waitPay OrderGoodBonusWaitPay) ModifyPertnerBonusPercent(good *OrderGood, percent float64, orderType int) error {
	//规则描述:
	//实际自建订单(orderType==1),未支付分红状态下“不可以”修改合伙人分红比例
	//香米小程序订单(orderType==3),未支付分红状态下“可以”修改合伙人分红比例
	switch orderType {
	case OrderReal:
		return errors.New("自建订单不能修改合伙人分红比例")
	case OrderTypeBestShop:
		good.PartnerBonusPercent = percent
		//待支付状态计算
		err := good.Compute()
		if err != nil {
			return errors.New("核算商品数据失败" + err.Error())
		}
		err = good.CurrentBonusStatus.WartPayPartnerBonus(good)
		if err != nil {
			return errors.New("核算商品数据失败" + err.Error())
		}
	}
	return nil
}

func (hasPay OrderGoodBonusHasPay) ModifyPertnerBonusPercent(good *OrderGood, percent float64, orderType int) error {
	//规则描述:
	//实际自建订单(orderType==1),已支付分红状态下“不可以”修改合伙人分红比例
	//香米小程序订单(orderType==3),已支付分红状态下“不可以”修改合伙人分红比例
	return errors.New("已支付分红的货品订单,不能修改合伙人分红比例")
}

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

//Compute 数据汇总核算
func (good *OrderGood) Compute() error {
	//计算预计货品总值
	//计算预计合伙人分红
	price := decimal.NewFromFloat(good.Price)
	planGoodNumber := good.PlanGoodNumber
	if good.PlanGoodNumber < 0 {
		planGoodNumber = 0
	}
	planamount := price.Mul(decimal.NewFromInt(int64(planGoodNumber))) //price*planGoodNumber
	var partnerBonusPercent float64
	if good.PartnerBonusPercent < 0 {
		partnerBonusPercent = 0
	} else {
		partnerBonusPercent = good.PartnerBonusPercent
	}
	//price*useGoodNumber
	planPartnerBonus := planamount.Mul(decimal.NewFromFloat(partnerBonusPercent)).Div(decimal.NewFromInt(100)) //price*planGoodNumber*PartnerBonusPercent
	good.GoodCompute.PlanAmount, _ = planamount.Round(2).BigFloat().Float64()
	good.GoodCompute.PlanPartnerBonus, _ = planPartnerBonus.Round(2).BigFloat().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(partnerBonusPercent)).Div(decimal.NewFromInt(100)) //price*useGoodNumber*PartnerBonusPercent
		good.GoodCompute.UsePartnerBonus, _ = usePartnerBonus.Round(2).BigFloat().Float64()
		good.GoodCompute.UseAmount, _ = useamount.Round(2).BigFloat().Float64()
	}

	return nil
}

type OrderGoodFindQuery struct {
	OrderId   int64
	Offset    int
	Limit     int
	CompanyId int64
}
type OrderGoodFindOneQuery struct {
	GoodId int64
}
type OrderGoodRepository interface {
	Save(order []OrderGood) error
	Find(queryOptions OrderGoodFindQuery) ([]OrderGood, int, error)
	FindOne(queryOptions OrderGoodFindOneQuery) (OrderGood, error)
	Remove(orderid int64, companyId int64, ids ...int64) error
}