Untitled
unknown
plain_text
10 months ago
7.7 kB
6
Indexable
package replenishment_inbound_order
import (
v2 "code.byted.org/oec/pbgen/go/oec/supply_chain/merchant/v2"
"code.byted.org/oec/rpcv2_oec_supply_chain_business_order/kitex_gen/oec/supply_chain/business_order_base"
"code.byted.org/oec/rpcv2_oec_supply_chain_planning_calc/kitex_gen/oec/supply_chain/planning_calc"
"code.byted.org/oec/rpcv2_oec_supply_chain_warehouse_meta/kitex_gen/oec/supply_chain/warehouse_meta"
"code.byted.org/oec/sc_merchant_gateway/consts"
"code.byted.org/oec/sc_merchant_gateway/internal/cerr"
"code.byted.org/oec/sc_merchant_gateway/util"
"context"
"sort"
"time"
)
func (i *ReplenishmentInboundOrderLogicImpl) GetReplenishmentAvailableInboundMethod(ctx context.Context, req *v2.GetReplenishmentAvailableInboundMethodRequest) (*v2.GetReplenishmentAvailableInboundMethodResponse, error) {
inboundOrderId := req.GetOrderId()
inboundOrderList, err := i.BusinessOrderClient.GetReplenishmentInboundOrder(ctx, []int64{inboundOrderId})
if err != nil {
return nil, err
}
if len(inboundOrderList) == 0 {
return nil, cerr.ErrNotExists{Key: "order"}
}
inboundOrder := inboundOrderList[0]
ipeReq := planning_calc.GetInboundMethodRequest{
MerchantId: inboundOrder.MerchantId,
EtaRangeList: buildTimeRangeForIpe(req.GetExpectedArrivalTimeRange().GetStart()),
GoodsUnits: int64(inboundOrder.GetExpectedCount()),
CartonCnt: int64(inboundOrder.GetCartonsQuantity()),
NeedInboundMethodList: []planning_calc.InboundMethod{
planning_calc.InboundMethod_D2FC,
planning_calc.InboundMethod_SingleHub,
planning_calc.InboundMethod_MultiHub,
},
}
timeRangeMap := i.GatewayConfig.GetInboundMethodTimeRangeConfig(ctx)
methodList, err := i.ReplPlanningCalcClient.GetInboundMethod(ctx, ipeReq)
if err != nil {
return nil, err
}
// get the warehouse data
warehouseIdList := make([]int64, 0)
sort.Slice(methodList.InboundMethodResultList, func(i, j int) bool {
return methodList.InboundMethodResultList[i].EtaRange.EtaStartTime < methodList.InboundMethodResultList[i].EtaRange.EtaStartTime
})
//the first element we need to get the warehouse list
for _, method := range methodList.InboundMethodResultList[0].InboundMethodDetailList {
if len(method.WarehouseIds) > 0 {
warehouseIdList = append(warehouseIdList, method.WarehouseIds...)
}
}
//get the earliest available week by other elements
nextAvailableWeekMap := buildNextAvailableWeek(methodList.GetInboundMethodResultList())
request := &warehouse_meta.GetWarehouseByIdsRequest{
WarehouseIds: warehouseIdList,
}
warehouseList, err := i.WarehouseClient.GetWarehouseMetaByIds(ctx, request)
if err != nil {
return nil, err
}
warehouseInfoMap := make(map[int64]*v2.WarehouseSimpleInfo)
for _, warehouseDetail := range warehouseList {
warehouseInfoMap[warehouseDetail.WarehouseBasicInfo.WarehouseId] = util.ConvertWarehouseInfo2WarehouseSimpleInfo(warehouseDetail)
}
availableMethodList := make([]*v2.AvailableInboundMethod, 0)
for _, method := range methodList.InboundMethodResultList[0].InboundMethodDetailList {
inboundMethod := v2.InboundMethod(method.InboundMethod)
earliestAppointmentDate, err := i.getAvailableAppointment(ctx, *method, inboundOrder)
if err != nil {
return nil, err
}
availableWarehouseList := make([]*v2.WarehouseSimpleInfo, 0)
for _, id := range method.GetWarehouseIds() {
availableWarehouseList = append(availableWarehouseList, warehouseInfoMap[id])
}
availableMethod := &v2.AvailableInboundMethod{
InboundMethod: inboundMethod,
Sla: &v2.TimeRange{
Start: timeRangeMap[inboundMethod].Min,
End: timeRangeMap[inboundMethod].Max,
},
ValidMethod: true,
EarliestAppointmentDate: earliestAppointmentDate,
OptionalWarehouseList: availableWarehouseList,
NextAvailableWeek: nextAvailableWeekMap[inboundMethod],
}
if len(availableWarehouseList) == 0 {
availableMethod.ValidMethod = false
}
availableMethodList = append(availableMethodList, availableMethod)
}
resp := &v2.GetReplenishmentAvailableInboundMethodResponse{
AvailableInboundMethodList: availableMethodList,
}
if err != nil {
return nil, err
}
return resp, nil
}
func (i *ReplenishmentInboundOrderLogicImpl) getAvailableAppointment(ctx context.Context, method planning_calc.InboundMethodDetail, inboundOrder *business_order_base.InboundOrder) (int64, error) {
appointmentTimeList := make([][]int64, 0)
for _, warehouseId := range method.WarehouseIds {
tempList := make([]int64, 0)
calendar, err := i.CapacityPlanClient.GetInboundCapacityCalendar(ctx, &v2.GetBookableTimeslotRequest{
InboundOrderId: inboundOrder.GetOrderId(),
WarehouseId: warehouseId,
ShippingMethod: v2.AppointmentShippingMethodType_APPOINTMENT_SHIPPING_METHOD_TYPE_PALLETIZED,
TimeRange: &v2.TimeRange{
Start: time.Now().UnixMilli(),
End: time.Now().UnixMilli() + consts.FOUR_WEEK_MILLI,
},
PalletCount: 1,
CartonCount: inboundOrder.GetCartonsQuantity(),
})
if err != nil {
return 0, nil
}
if calendar == nil || len(calendar.CapacityList) <= 0 ||
len(calendar.CapacityList[0].DaysCapacity) <= 0 {
return consts.EARLIEST_APPOINTMENT_DATE, nil
}
targetDayCapacity := calendar.CapacityList[0].DaysCapacity[0].WaveList
for _, item := range targetDayCapacity {
if item.AvailableCapacity > 0 {
tempList = append(tempList, item.StartTime)
}
}
if len(tempList) == 0 {
return consts.EARLIEST_APPOINTMENT_DATE, cerr.ErrValidation{Message: "no appointment is available for next four weeks"}
}
appointmentTimeList = append(appointmentTimeList, tempList)
}
appointmentTime, err := findLatestAppointment(appointmentTimeList)
if err != nil {
return 0, err
}
return appointmentTime, nil
}
func findLatestAppointment(allTimes [][]int64) (int64, error) {
var maxTime int64 = 0
for _, times := range allTimes {
for _, t := range times {
if t > maxTime {
maxTime = t
}
}
}
return daysUntil(maxTime), nil
}
func daysUntil(maxTime int64) int64 {
latestDate := time.UnixMilli(maxTime).UTC()
today := time.Now().UTC()
todayDateOnly := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, time.UTC)
latestDateOnly := time.Date(latestDate.Year(), latestDate.Month(), latestDate.Day(), 0, 0, 0, 0, time.UTC)
days := latestDateOnly.Sub(todayDateOnly).Hours() / 24
return int64(days)
}
func buildTimeRangeForIpe(start int64) []*planning_calc.EtaRange {
var ranges []*planning_calc.EtaRange
// Start time in seconds (assuming input is in milliseconds)
startTime := time.Unix(start/1000, 0)
// Adjust start time to the beginning of the next Sunday unless it's already a Sunday
if startTime.Weekday() != time.Sunday {
startTime = startTime.AddDate(0, 0, int(time.Sunday-startTime.Weekday()))
}
// Weekly duration in seconds
oneWeek := int64(time.Hour * 24 * 7 / time.Second)
// Generate weekly ranges for eight weeks
for week := 0; week < 8; week++ {
currentStart := startTime.Add(time.Duration(week) * time.Duration(oneWeek)).Unix()
currentEnd := currentStart + oneWeek - 1
ranges = append(ranges, &planning_calc.EtaRange{
EtaStartTime: currentStart,
EtaEndTime: currentEnd,
})
}
return ranges
}
func buildNextAvailableWeek(inboundMethodResult []*planning_calc.InboundMethodResult_) map[v2.InboundMethod]int64 {
respMap := make(map[v2.InboundMethod]int64)
for week, list := range inboundMethodResult {
for _, result := range list.InboundMethodDetailList {
if result.WarehouseIds != nil && len(result.GetWarehouseIds()) > 0 && respMap[v2.InboundMethod(result.GetInboundMethod())] != 0 {
respMap[v2.InboundMethod(result.GetInboundMethod())] = int64(week)
}
}
}
return respMap
}
Editor is loading...
Leave a Comment