Files
jx-callback/business/partner/partner.go
2019-06-06 10:35:06 +08:00

365 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package partner
import (
"errors"
"fmt"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
const (
StoreNameSeparator = "-"
)
const (
CreatedPeration = "create"
UpdatedPeration = "update"
)
const (
CancelWaybillReasonNotAcceptIntime = 1
CancelWaybillReasonSwitch2SelfFailed = 2
CancelWaybillReasonOther = 10
)
const (
PrinterStatusUnknown = 0
PrinterStatusOffline = 1
PrinterStatusOnlineOK = 2
PrinterStatusOnlineAbnormal = 3
)
const (
AfsApproveTypeRefund = 1 // 退款
AfsApproveTypeReturnGoods = 2 // 退货
AfsApproveTypeRefused = 3 // 驳回
)
const (
PrintResultSuccess = 0
PrintResultNoPrinter = 1
)
type PrinterStatus struct {
PrintResult int `json:"printResult"` // 0成功1没有配置网络打印机
// PrinterStatusUnknown = 0
// PrinterStatusOffline = 1
// PrinterStatusOnlineOK = 2
// PrinterStatusOnlineAbnormal = 3
PrinterStatus int `json:"printerStatus"`
Printed int `json:"printed"` // 已经打印的单数
Waiting int `json:"waiting"` // 等待打印的单数超过1一般不太正常
}
const (
TimerTypeNoOverride = 0 // GetStatusActionConfig 返回表示不修改缺省配置
TimerTypeByPass = 1
TimerTypeBaseNow = 2
TimerTypeBaseStatusTime = 3
TimerTypeBaseOrderCreatedAt = 4
)
type StatusActionParams struct {
TimerType int // 参见上面的相关常量定义
Timeout time.Duration // 超时时间0在GetStatusActionConfig返回时表示不修改缺省
TimeoutGap int // 以秒为单位的随机时间0在GetStatusActionConfig返回时表示不修改缺省
}
const (
WaybillFeeErrCodeCourierNotOpen = 1 //配送门店没有启用
WaybillFeeErrCodeCourierNotSupported = 2 //配送门店不被系统支持
WaybillFeeErrCodeCourierForbidden = 3 //配送门店内部禁用
WaybillFeeErrCodeCourierOthers = 10 //其它错误
)
type WaybillFeeInfo struct {
ErrCode int `json:"errCode"`
ErrStr string `json:"errStr"`
RefDeliveryFee int64 `json:"refDeliveryFee"`
RefAddFee int64 `json:"refAddFee"`
DeliveryFee int64 `json:"deliveryFee"`
TimeoutSecond int `json:"timeoutSecond"` // 系统会自动发运单的倒计时
Waybill *model.Waybill `json:"waybill"`
}
func (s *StatusActionParams) GetRefTimeout(statusTime time.Time, orderCreatedAt time.Time) (timeout time.Duration) {
switch s.TimerType {
case TimerTypeBaseNow:
timeout = s.Timeout
case TimerTypeBaseStatusTime:
timeout = statusTime.Sub(time.Now()) + s.Timeout
case TimerTypeBaseOrderCreatedAt:
timeout = orderCreatedAt.Sub(time.Now()) + s.Timeout
default:
timeout = 0
}
if timeout < 0 {
timeout = 0
}
return timeout
}
var (
CancelWaybillReasonStrNotAcceptIntime = "没有及时抢单"
CancelWaybillReasonStrSwitch2SelfFailed = "转自送失败"
CancelWaybillReasonStrOrderAlreadyFinished = "订单已经结束"
CancelWaybillReasonStrActive = "操作由人员主动发起"
)
var (
ErrCanNotFindItem = errors.New("没有找到指定的东西")
ErrStoreHaveNoCourier = errors.New("门店没有绑定相应的配送信息")
)
var (
CurOrderManager IOrderManager
CurStoreManager IStoreManager
PurchasePlatformHandlers map[int]IPurchasePlatformHandler
DeliveryPlatformHandlers map[int]*DeliveryPlatformHandlerInfo
UseableDeliveryVendorIDs []int
PrinterPlatformHandlers map[int]IPrinterHandler
)
type IOrderManager interface {
SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao.DaoDB) (isDuplicated bool, err error)
OnOrderNew(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error)
OnOrderAdjust(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error)
OnOrderStatusChanged(orderStatus *model.OrderStatus) (err error)
OnOrderMsg(order *model.GoodsOrder, vendorStatus, remark string) (err error)
OnWaybillStatusChanged(bill *model.Waybill) (err error)
LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error)
LoadOrder2(vendorOrderID2 string, vendorID int) (order *model.GoodsOrder, err error)
LoadOrderFinancial(vendorOrderID string, vendorID int) (order *model.OrderFinancial, err error)
LoadOrderFinancial2(vendorOrderID2 string, vendorID int) (order *model.OrderFinancial, err error)
UpdateOrderStatusAndDeliveryFlag(order *model.GoodsOrder) (err error)
UpdateOrderFields(order *model.GoodsOrder, fieldList []string) (err error)
LoadWaybill(vendorWaybillID string, waybillVendorID int) (bill *model.Waybill, err error)
OnOrderComments(orderCommentList []*model.OrderComment) (err error)
SaveOrderFinancialInfo(order *model.OrderFinancial, operation string) (err error)
SaveAfsOrderFinancialInfo(afsOrder *model.AfsOrder) (err error)
GetOrderWaybillInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isNotEnded bool) (bills []*model.Waybill, err error)
// afs order
OnAfsOrderAdjust(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error)
OnAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error)
OnAfsOrderStatusChanged(orderStatus *model.OrderStatus) (err error)
LoadAfsOrder(vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error)
UpdateAfsOrderFields(afsOrder *model.AfsOrder, fieldList []string) (err error)
GetStatusDuplicatedCount(status *model.OrderStatus) (duplicatedCount int)
}
type IStoreManager interface {
OnStoreStatusChanged(vendorStoreID string, vendorID int, storeStatus int) (err error)
}
// purchase handler中
// 所有SyncRefresh开头的函数都必须自己清理sync_status标记
// 所有非以SyncRefresh开头的函数不用自己清理sync_status标记VendorSync统一处理
type IPurchasePlatformHandler interface {
// IPurchasePlatformPromotionHandler
GetVendorID() int
GetStatusFromVendorStatus(vendorStatus string) int
Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder)
GetOrder(vendorOrderID string) (order *model.GoodsOrder, err error)
GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *StatusActionParams)
AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error)
PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error)
AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error)
CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) // 取货失败后再次招唤平台配送
ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) // 投递失败后确认收到退货
// 将订单从购物平台配送转为自送
Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error)
// 将订单从购物平台配送转为自送后又送达
Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error)
// 完全自送的门店表示开始配送
SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error)
// 完全自送的门店表示配送完成
SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error)
GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error)
ReplyOrderComment(ctx *jxcontext.Context, orderComment *model.OrderComment, replyComment string) (err error)
AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error)
CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error)
// order.Skus要包含原始订单中的Sku信息removedSkuList中是要移除的Sku信息
AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error)
// 售后
// // 发起全款退款
// RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error)
// // 发起部分退款
// PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error)
// 审核售后单申请
AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error)
// // 确认收到退货
ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error)
////////
// Store
ReadStore(vendorStoreID string) (store *model.Store, err error)
UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error)
// EnableAutoAcceptOrder(vendorStoreID string, isEnabled bool) error
// OpenStore(vendorStoreID string, userName string) error
// CloseStore(vendorStoreID, closeNotice, userName string) error
SyncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error)
RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error)
// !!!注意,此操作会先清除门店已有的商品,一般用于初始化,小心使用
FullSyncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync, isContinueWhenError bool) (hint string, err error)
DeleteRemoteStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync, isContinueWhenError bool) (hint string, err error)
UploadImg(ctx *jxcontext.Context, imgURL string, imgData []byte, imgName string) (imgHint string, err error)
GetStoreStatus(ctx *jxcontext.Context, vendorStoreID string) (storeStatus int, err error)
GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error)
// todo 如下两个函数需要合并一下s
GetStoresSku(ctx *jxcontext.Context, parentTask tasksch.ITask, storeIDs []int) (storeSkuList []*model.StoreSkuBind, err error)
GetStoreSkusInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*BareStoreSkuInfo) (outStoreSkuList []*BareStoreSkuInfo, err error)
}
// db *dao.DaoDB,
type IMultipleStoresHandler interface {
IPurchasePlatformHandler
ReadCategories() (cats []*model.SkuCategory, err error)
CreateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error)
UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error
DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error
ReorderCategories(db *dao.DaoDB, parentCatID int, userName string) (err error)
// sku
CreateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error)
ReadSku(vendorSkuID string) (skuNameExt *model.SkuNameExt, err error)
UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error)
DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error)
RefreshAllSkusID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error)
}
type ISingleStoreHandler interface {
IPurchasePlatformHandler
SyncStoreCategory(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync bool) (hint string, err error)
RefreshStoresAllSkusID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool, storeIDs []int) (hint string, err error)
}
type CreateWaybillPolicy func(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string)
type IDeliveryPlatformHandler interface {
CreateWaybill(order *model.GoodsOrder, policy CreateWaybillPolicy) (bill *model.Waybill, err error)
CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error)
GetVendorID() int
GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *WaybillFeeInfo, err error)
}
type IPrinterHandler interface {
GetVendorID() int
PrintMsg(ctx *jxcontext.Context, id1, id2, msgTitle, msgContent string) (printerStatus *PrinterStatus, err error)
GetPrinterStatus(ctx *jxcontext.Context, id1, id2 string) (printerStatus *PrinterStatus, err error)
RegisterPrinter(ctx *jxcontext.Context, id1, id2, printerName string) (newID1, newID2 string, err error)
UnregisterPrinter(ctx *jxcontext.Context, id1, id2 string) (err error)
PrintOrder(ctx *jxcontext.Context, store *model.Store, order *model.GoodsOrder) (printerStatus *PrinterStatus, err error)
}
type DeliveryPlatformHandlerInfo struct {
Handler IDeliveryPlatformHandler
Use4CreateWaybill bool
}
type BasePurchasePlatform struct {
}
func (p *BasePurchasePlatform) GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *StatusActionParams) {
return params
}
func init() {
PurchasePlatformHandlers = make(map[int]IPurchasePlatformHandler)
DeliveryPlatformHandlers = make(map[int]*DeliveryPlatformHandlerInfo)
PrinterPlatformHandlers = make(map[int]IPrinterHandler)
}
func InitOrderManager(curOrderManager IOrderManager) {
CurOrderManager = curOrderManager
}
func InitStoreManager(curStoreManager IStoreManager) {
CurStoreManager = curStoreManager
}
func RegisterPurchasePlatform(handler IPurchasePlatformHandler) {
vendorID := handler.GetVendorID()
if !(model.IsPurchaseVendorExist(vendorID)) {
panic(fmt.Sprintf("purchase vendor:%d is illegal", vendorID))
}
if _, ok := PurchasePlatformHandlers[vendorID]; ok {
panic(fmt.Sprintf("purchase vendor:%d, already exists", vendorID))
}
PurchasePlatformHandlers[vendorID] = handler
}
func RegisterDeliveryPlatform(handler IDeliveryPlatformHandler, isUse4CreateWaybill bool) {
vendorID := handler.GetVendorID()
if !(model.IsDeliveryVendorExist(vendorID)) {
panic(fmt.Sprintf("delivery vendor:%d is illegal", vendorID))
}
if _, ok := DeliveryPlatformHandlers[vendorID]; ok {
panic(fmt.Sprintf("delivery vendor:%d, already exists", vendorID))
}
DeliveryPlatformHandlers[vendorID] = &DeliveryPlatformHandlerInfo{
Handler: handler,
Use4CreateWaybill: isUse4CreateWaybill,
}
UseableDeliveryVendorIDs = append(UseableDeliveryVendorIDs, vendorID)
}
func RegisterPrinterPlatform(handler IPrinterHandler) {
vendorID := handler.GetVendorID()
if !(model.IsPrinterVendorExist(vendorID)) {
panic(fmt.Sprintf("printer vendor:%d is illegal", vendorID))
}
if _, ok := PrinterPlatformHandlers[vendorID]; ok {
panic(fmt.Sprintf("printer vendor:%d, already exists", vendorID))
}
PrinterPlatformHandlers[vendorID] = handler
}
func GetPurchasePlatformFromVendorID(vendorID int) IPurchasePlatformHandler {
return PurchasePlatformHandlers[vendorID]
}
func GetDeliveryPlatformFromVendorID(vendorID int) *DeliveryPlatformHandlerInfo {
return DeliveryPlatformHandlers[vendorID]
}
func GetPrinterPlatformFromVendorID(vendorID int) IPrinterHandler {
return PrinterPlatformHandlers[vendorID]
}