From 6ae2cce870ad4178464a3f982bfbdf199ee28c85 Mon Sep 17 00:00:00 2001 From: momo <1012651275@qq.com> Date: Tue, 17 Oct 2023 18:32:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9E=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=8F=91=E7=A5=A8,=E4=B8=8B=E5=8D=95=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- constants/invoice_html.go | 68 ++-- constants/orders.go | 7 + model/gmodel/fs_admin_role_gen.go | 2 +- model/gmodel/fs_department_gen.go | 1 + model/gmodel/fs_font_gen.go | 4 +- model/gmodel/fs_order_gen.go | 3 + model/gmodel/fs_order_logic.go | 11 +- model/gmodel/fs_order_trade_gen.go | 1 + model/gmodel/fs_product_gen.go | 1 + server/order/internal/config/config.go | 9 + .../internal/handler/orderinvoicehandler.go | 35 ++ server/order/internal/handler/routes.go | 5 + .../logic/createprepaymentbydepositlogic.go | 18 +- .../order/internal/logic/orderinvoicelogic.go | 57 +++ server/order/internal/svc/servicecontext.go | 9 +- server/order/internal/types/types.go | 15 +- server/order/invoice.html | 281 +++++++++++++++ .../internal/logic/logocombinelogic.go | 8 +- server_api/order.api | 22 +- service/repositories/order.go | 337 +++++++++++++++++- utils/basic/basic.go | 1 + utils/order/order.go | 7 +- utils/order/order_invoice.go | 5 + 23 files changed, 848 insertions(+), 59 deletions(-) create mode 100644 server/order/internal/handler/orderinvoicehandler.go create mode 100644 server/order/internal/logic/orderinvoicelogic.go create mode 100644 server/order/invoice.html create mode 100644 utils/order/order_invoice.go diff --git a/constants/invoice_html.go b/constants/invoice_html.go index d6181ef1..6e4417a8 100644 --- a/constants/invoice_html.go +++ b/constants/invoice_html.go @@ -1,6 +1,6 @@ package constants -const INVOICE_TEMPLATE = ` +const INVOICE_TEMPLATE_01 = ` @@ -192,29 +192,34 @@ const INVOICE_TEMPLATE = ` Invoice +` + +const INVOICE_TEMPLATE_02 = ` - + - - + + - + - + - +
Bill To:Invoice No. #20220562040Invoice No. #%v
Timmy TurnerDate: 2023/12/04%vDate: %v
North Street%v
London, SE20 3JW%v
United Kingdom%v
+` +const INVOICE_TEMPLATE_03 = ` @@ -223,24 +228,24 @@ const INVOICE_TEMPLATE = ` - - - - - - - - - - - - + %v
Quantity Total
Plastic bowl$01.0020,000 Units$99.00
Paper bag with handlexxxxxxxxxxxxxxx second line$01.0020,000 Units$99.00
+` + +const INVOICE_TEMPLATE_0301 = ` + + %v + %v + %v Units + %v + +` +const INVOICE_TEMPLATE_04 = ` - + @@ -248,21 +253,23 @@ const INVOICE_TEMPLATE = ` - + - + - - + + - - + +
Subtotal$198.00%v
Shipping Fee
Tax$0.00%v
Total$198.00%v
Deposit Requested$99.00%v%v
Deposit Due$99.00%v%v
+` +const INVOICE_TEMPLATE_05 = ` @@ -270,15 +277,18 @@ const INVOICE_TEMPLATE = ` - + - +
Notes:
ICBC%v Thank you for your business !
Account No. :****4589Account No. :%v
+ ` +const INVOICE_TEMPLATE_06 = ` - ` + +` diff --git a/constants/orders.go b/constants/orders.go index 1474574f..5bcfebca 100644 --- a/constants/orders.go +++ b/constants/orders.go @@ -92,7 +92,14 @@ var OrderStatusUserDIRECTMAIL []OrderStatusCode // 订单状态--用户可见--云仓 var OrderStatusUserCLOUDSTORE []OrderStatusCode +// 订单货币 +var OrderCurrencyMessage map[Currency]string + func init() { + // 订单货币 + OrderCurrencyMessage = make(map[Currency]string, 1) + OrderCurrencyMessage[CURRENCYUSD] = "$" + // 订单状态名称 OrderPayStatusMessage = make(map[OrderPayStatusCode]string) OrderPayStatusMessage[ORDER_PAY_STATUS_UNPAIDDEPOSIT] = "Deposit Payment Unpaid" diff --git a/model/gmodel/fs_admin_role_gen.go b/model/gmodel/fs_admin_role_gen.go index 498a4a09..79b28060 100644 --- a/model/gmodel/fs_admin_role_gen.go +++ b/model/gmodel/fs_admin_role_gen.go @@ -11,7 +11,7 @@ type FsAdminRole struct { RolePid *int64 `gorm:"default:0;" json:"role_pid"` // 上级角色 RoleName *string `gorm:"unique_key;default:'';" json:"role_name"` // DataAuthType *int64 `gorm:"default:1;" json:"data_auth_type"` // 数据权限类型 - DataAuth *string `gorm:"default:'';" json:"data_auth"` // + DataAuth *[]byte `gorm:"default:'';" json:"data_auth"` // Status *int64 `gorm:"default:2;" json:"status"` // 状态:1=启用,2=停用 Remark *string `gorm:"default:'';" json:"remark"` // Sort *int64 `gorm:"default:0;" json:"sort"` // 排序权重 diff --git a/model/gmodel/fs_department_gen.go b/model/gmodel/fs_department_gen.go index 7ce37951..58c40c2a 100644 --- a/model/gmodel/fs_department_gen.go +++ b/model/gmodel/fs_department_gen.go @@ -11,6 +11,7 @@ type FsDepartment struct { Status *int64 `gorm:"default:0;" json:"status"` // 状态 1正常0停用 Ctime *int64 `gorm:"default:0;" json:"ctime"` // 添加时间 ParentId *int64 `gorm:"default:0;" json:"parent_id"` // 父级id + Manager *int64 `gorm:"default:0;" json:"manager"` // 负责人 } type FsDepartmentModel struct { db *gorm.DB diff --git a/model/gmodel/fs_font_gen.go b/model/gmodel/fs_font_gen.go index 02f5b748..15bb89de 100644 --- a/model/gmodel/fs_font_gen.go +++ b/model/gmodel/fs_font_gen.go @@ -7,9 +7,9 @@ import ( // fs_font 字体配置 type FsFont struct { Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id - Title *string `gorm:"default:'';" json:"title"` // 字体名字 + Title *string `gorm:"default:'';" json:"title"` // LinuxFontname *string `gorm:"default:'';" json:"linux_fontname"` // linux对应字体名 - FilePath *string `gorm:"default:'';" json:"file_path"` // 字体文件路径 + FilePath *string `gorm:"default:'';" json:"file_path"` // Sort *int64 `gorm:"default:0;" json:"sort"` // 排序 } type FsFontModel struct { diff --git a/model/gmodel/fs_order_gen.go b/model/gmodel/fs_order_gen.go index 3329dc28..1af42fde 100644 --- a/model/gmodel/fs_order_gen.go +++ b/model/gmodel/fs_order_gen.go @@ -25,6 +25,9 @@ type FsOrder struct { PayStatusLink *[]byte `gorm:"default:'';" json:"pay_status_link"` // ShoppingCartSnapshot *[]byte `gorm:"default:'';" json:"shopping_cart_snapshot"` // ShoppingProductSnapshot *[]byte `gorm:"default:'';" json:"shopping_product_snapshot"` // + SaleGerentId *int64 `gorm:"default:0;" json:"sale_gerent_id"` // 销售负责人 + DesignGerentId *int64 `gorm:"default:0;" json:"design_gerent_id"` // 设计负责人 + Scm *[]byte `gorm:"default:'';" json:"scm"` // } type FsOrderModel struct { db *gorm.DB diff --git a/model/gmodel/fs_order_logic.go b/model/gmodel/fs_order_logic.go index 1a5cb01e..b29b3b81 100644 --- a/model/gmodel/fs_order_logic.go +++ b/model/gmodel/fs_order_logic.go @@ -19,9 +19,14 @@ type OrderDetail struct { // 收货地址 type OrderAddress struct { - Address string `json:"address"` // 详细地址 - Mobile string `json:"mobile"` // 手机 - Name string `json:"name"` // 姓名 + Street string `json:"street"` // 详细地址 + City string `json:"city"` // 城市 + FirstName string `json:"first_name"` // 姓 + LastName string `json:"last_name"` // 名 + Mobile string `json:"mobile"` // 手机 + State string `json:"state"` // 州 + Suite string `json:"suite"` // 房号 + ZipCode string `json:"zip_code"` // 邮编号码 } // 订单金额 diff --git a/model/gmodel/fs_order_trade_gen.go b/model/gmodel/fs_order_trade_gen.go index 0e3abc15..52abfc53 100644 --- a/model/gmodel/fs_order_trade_gen.go +++ b/model/gmodel/fs_order_trade_gen.go @@ -25,6 +25,7 @@ type FsOrderTrade struct { Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` // PayTitle *string `gorm:"default:'';" json:"pay_title"` // + ReceiptSn *string `gorm:"default:'';" json:"receipt_sn"` // } type FsOrderTradeModel struct { db *gorm.DB diff --git a/model/gmodel/fs_product_gen.go b/model/gmodel/fs_product_gen.go index 6185e7a9..f2e5d931 100644 --- a/model/gmodel/fs_product_gen.go +++ b/model/gmodel/fs_product_gen.go @@ -37,6 +37,7 @@ type FsProduct struct { SceneIds *string `gorm:"default:'';" json:"scene_ids"` // IsCustomization *int64 `gorm:"default:0;" json:"is_customization"` // 是否可定制 Unit *string `gorm:"default:'';" json:"unit"` // + SupplyChainManager *int64 `gorm:"default:0;" json:"supply_chain_manager"` // 供应链负责人 } type FsProductModel struct { db *gorm.DB diff --git a/server/order/internal/config/config.go b/server/order/internal/config/config.go index 8ebf0d57..d6bea003 100644 --- a/server/order/internal/config/config.go +++ b/server/order/internal/config/config.go @@ -19,4 +19,13 @@ type Config struct { SuccessURL string } } + AWS struct { + S3 struct { + Credentials struct { + AccessKeyID string + Secret string + Token string + } + } + } } diff --git a/server/order/internal/handler/orderinvoicehandler.go b/server/order/internal/handler/orderinvoicehandler.go new file mode 100644 index 00000000..3d85e89c --- /dev/null +++ b/server/order/internal/handler/orderinvoicehandler.go @@ -0,0 +1,35 @@ +package handler + +import ( + "net/http" + "reflect" + + "fusenapi/utils/basic" + + "fusenapi/server/order/internal/logic" + "fusenapi/server/order/internal/svc" + "fusenapi/server/order/internal/types" +) + +func OrderInvoiceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var req types.OrderInvoiceReq + userinfo, err := basic.RequestParse(w, r, svcCtx, &req) + if err != nil { + return + } + + // 创建一个业务逻辑层实例 + l := logic.NewOrderInvoiceLogic(r.Context(), svcCtx) + + rl := reflect.ValueOf(l) + basic.BeforeLogic(w, r, rl) + + resp := l.OrderInvoice(&req, userinfo) + + if !basic.AfterLogic(w, r, rl, resp) { + basic.NormalAfterLogic(w, r, resp) + } + } +} diff --git a/server/order/internal/handler/routes.go b/server/order/internal/handler/routes.go index f3dc8b2b..0df4a436 100644 --- a/server/order/internal/handler/routes.go +++ b/server/order/internal/handler/routes.go @@ -37,6 +37,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/api/order/close", Handler: CloseOrderHandler(serverCtx), }, + { + Method: http.MethodGet, + Path: "/api/order/invoice", + Handler: OrderInvoiceHandler(serverCtx), + }, { Method: http.MethodGet, Path: "/api/order/list", diff --git a/server/order/internal/logic/createprepaymentbydepositlogic.go b/server/order/internal/logic/createprepaymentbydepositlogic.go index 584c3511..602f37cc 100644 --- a/server/order/internal/logic/createprepaymentbydepositlogic.go +++ b/server/order/internal/logic/createprepaymentbydepositlogic.go @@ -43,16 +43,28 @@ func (l *CreatePrePaymentByDepositLogic) CreatePrePaymentByDeposit(req *types.Cr if req.DeliveryAddress == nil { return resp.SetStatus(basic.CodeErrOrderCreatePrePaymentParam) } else { - if req.DeliveryAddress.Address == "" || req.DeliveryAddress.Mobile == "" || req.DeliveryAddress.Name == "" { + if req.DeliveryAddress.Street == "" || + req.DeliveryAddress.City == "" || + req.DeliveryAddress.Mobile == "" || + req.DeliveryAddress.State == "" || + req.DeliveryAddress.Suite == "" || + req.DeliveryAddress.ZipCode == "" || + req.DeliveryAddress.LastName == "" || + req.DeliveryAddress.FirstName == "" { return resp.SetStatus(basic.CodeErrOrderCreatePrePaymentParam) } } } var orderAddress repositories.OrderAddress if req.DeliveryAddress != nil { - orderAddress.Address = req.DeliveryAddress.Address + orderAddress.Street = req.DeliveryAddress.Street + orderAddress.City = req.DeliveryAddress.City + orderAddress.FirstName = req.DeliveryAddress.FirstName + orderAddress.LastName = req.DeliveryAddress.LastName orderAddress.Mobile = req.DeliveryAddress.Mobile - orderAddress.Name = req.DeliveryAddress.Name + orderAddress.State = req.DeliveryAddress.State + orderAddress.Suite = req.DeliveryAddress.Suite + orderAddress.ZipCode = req.DeliveryAddress.ZipCode } res, err := l.svcCtx.Repositories.NewOrder.CreatePrePaymentByDeposit(l.ctx, &repositories.CreatePrePaymentByDepositReq{ UserId: userinfo.UserId, diff --git a/server/order/internal/logic/orderinvoicelogic.go b/server/order/internal/logic/orderinvoicelogic.go new file mode 100644 index 00000000..8cbb2d11 --- /dev/null +++ b/server/order/internal/logic/orderinvoicelogic.go @@ -0,0 +1,57 @@ +package logic + +import ( + "fusenapi/service/repositories" + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "context" + + "fusenapi/server/order/internal/svc" + "fusenapi/server/order/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type OrderInvoiceLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewOrderInvoiceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OrderInvoiceLogic { + return &OrderInvoiceLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +// 处理进入前逻辑w,r +// func (l *OrderInvoiceLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) { +// } + +func (l *OrderInvoiceLogic) OrderInvoice(req *types.OrderInvoiceReq, userinfo *auth.UserInfo) (resp *basic.Response) { + // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) + // userinfo 传入值时, 一定不为null + if !userinfo.IsUser() { + // 如果是,返回未授权的错误码 + return resp.SetStatus(basic.CodeUnAuth) + } + res, err := l.svcCtx.Repositories.NewOrder.Invoice(l.ctx, &repositories.InvoiceReq{ + OrderSn: req.OrderSn, + UserId: userinfo.UserId, + }) + if err != nil { + return resp.SetStatus(&res.ErrorCode) + } + + return resp.SetStatus(basic.CodeOK, map[string]interface{}{ + "invoice_urls": res.InvoiceUrls, + }) +} + +// 处理逻辑后 w,r 如:重定向, resp 必须重新处理 +// func (l *OrderInvoiceLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) { +// // httpx.OkJsonCtx(r.Context(), w, resp) +// } diff --git a/server/order/internal/svc/servicecontext.go b/server/order/internal/svc/servicecontext.go index e109170c..a1ca8ca9 100644 --- a/server/order/internal/svc/servicecontext.go +++ b/server/order/internal/svc/servicecontext.go @@ -7,6 +7,9 @@ import ( "fusenapi/initalize" "fusenapi/model/gmodel" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" "gorm.io/gorm" ) @@ -20,10 +23,14 @@ type ServiceContext struct { } func NewServiceContext(c config.Config) *ServiceContext { + configAWS := aws.Config{ + Credentials: credentials.NewStaticCredentials(c.AWS.S3.Credentials.AccessKeyID, c.AWS.S3.Credentials.Secret, c.AWS.S3.Credentials.Token), + } conn := initalize.InitMysql(c.SourceMysql) // delayQueue := initalize.InitDelayMessage() repositories := initalize.NewAllRepositories(&initalize.NewAllRepositorieData{ - GormDB: conn, + GormDB: conn, + AwsSession: session.Must(session.NewSession(&configAWS)), // DelayQueue: delayQueue, }) diff --git a/server/order/internal/types/types.go b/server/order/internal/types/types.go index 02480c1b..f2f488e6 100644 --- a/server/order/internal/types/types.go +++ b/server/order/internal/types/types.go @@ -5,6 +5,10 @@ import ( "fusenapi/utils/basic" ) +type OrderInvoiceReq struct { + OrderSn string `form:"order_sn"` +} + type CloseOrderReq struct { OrderSn string `json:"order_sn"` } @@ -28,9 +32,14 @@ type CreatePrePaymentByDepositReq struct { } type DeliveryAddress struct { - Address string `json:"address,optional"` - Name string `json:"name,optional"` - Mobile string `json:"mobile,optional"` + Street string `json:"street,optional"` // 街道 + City string `json:"city,optional"` // 城市 + FirstName string `json:"first_name,optional"` // 姓 + LastName string `json:"last_name,optional"` // 名 + Mobile string `json:"mobile,optional"` // 手机 + State string `json:"state,optional"` // 州 + Suite string `json:"suite,optional"` // 房号 + ZipCode string `json:"zip_code,optional"` // 邮编 } type CreatePrePaymentByBalanceReq struct { diff --git a/server/order/invoice.html b/server/order/invoice.html new file mode 100644 index 00000000..6867e884 --- /dev/null +++ b/server/order/invoice.html @@ -0,0 +1,281 @@ + + + + + + + + Invoice + + + + + + + + + + +
Invoice
+ + + + + + + + + + + + + + + + + + + + + + +
Bill To:Invoice No. #20220562040
Timmy TurnerDate: 2023/12/04
North Street
London, SE20 3JW
United Kingdom
+ + + + + + + + + + + + + + + + + + + + + + +
Product NamePriceQuantityTotal
Plastic bowl$01.0020,000 Units$99.00
Paper bag with handlexxxxxxxxxxxxxxx second line$01.0020,000 Units$99.00
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Subtotal$198.00
Shipping FeeFree
Tax$0.00
Total$198.00
Deposit Requested$99.00
Deposit Due$99.00
+ + + + + + + + + + + + + +
Payment Method:Notes:
ICBCThank you for your business !
Account No. :20000000001
+ + + \ No newline at end of file diff --git a/server/resource/internal/logic/logocombinelogic.go b/server/resource/internal/logic/logocombinelogic.go index de3367cc..609a4316 100644 --- a/server/resource/internal/logic/logocombinelogic.go +++ b/server/resource/internal/logic/logocombinelogic.go @@ -43,10 +43,10 @@ func (l *LogoCombineLogic) LogoCombine(req *types.LogoCombineReq, userinfo *auth // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // userinfo 传入值时, 一定不为null - if userinfo.IsOnlooker() { - // 如果是,返回未授权的错误码 - return resp.SetStatus(basic.CodeUnAuth) - } + // if userinfo.IsOnlooker() { + // // 如果是,返回未授权的错误码 + // return resp.SetStatus(basic.CodeUnAuth) + // } if req.TemplateId == 0 || req.TemplateTag == "" { return resp.SetStatus(basic.CodeLogoCombineNoFoundErr, "模版或标签不存在") diff --git a/server_api/order.api b/server_api/order.api index 4e62ecd3..b0536334 100644 --- a/server_api/order.api +++ b/server_api/order.api @@ -24,7 +24,10 @@ service order { post /api/order/delete(DeleteOrderReq) returns (response); @handler CloseOrderHandler - post /api/order/close(CloseOrderReq) returns (response); + post /api/order/close(CloseOrderReq) returns (response) + + @handler OrderInvoiceHandler + get /api/order/invoice(OrderInvoiceReq) returns (response); @handler OrderListHandler get /api/order/list(OrderListReq) returns (response); @@ -34,6 +37,12 @@ service order { } +type ( + OrderInvoiceReq { + OrderSn string `form:"order_sn"` + } +) + type ( CloseOrderReq { OrderSn string `json:"order_sn"` @@ -60,9 +69,14 @@ type CreatePrePaymentByDepositReq { } type DeliveryAddress { - Address string `json:"address,optional"` - Name string `json:"name,optional"` - Mobile string `json:"mobile,optional"` + Street string `json:"street,optional"` // 街道 + City string `json:"city,optional"` // 城市 + FirstName string `json:"first_name,optional"` // 姓 + LastName string `json:"last_name,optional"` // 名 + Mobile string `json:"mobile,optional"` // 手机 + State string `json:"state,optional"` // 州 + Suite string `json:"suite,optional"` // 房号 + ZipCode string `json:"zip_code,optional"` // 邮编 } type CreatePrePaymentByBalanceReq { diff --git a/service/repositories/order.go b/service/repositories/order.go index 325b90b8..da49c782 100644 --- a/service/repositories/order.go +++ b/service/repositories/order.go @@ -8,9 +8,12 @@ import ( "fusenapi/constants" "fusenapi/model/gmodel" "fusenapi/utils/basic" + "fusenapi/utils/file" "fusenapi/utils/handlers" + "fusenapi/utils/hash" "fusenapi/utils/order" "fusenapi/utils/pay" + "fusenapi/utils/pdf" "fusenapi/utils/queue" "math" "time" @@ -25,6 +28,7 @@ func NewOrder(gormDB *gorm.DB, awsSession *session.Session, delayQueue *queue.De return &defaultOrder{ MysqlConn: gormDB, DelayQueue: delayQueue, + AwsSession: awsSession, } } @@ -32,6 +36,7 @@ type ( defaultOrder struct { MysqlConn *gorm.DB DelayQueue *queue.DelayMessage + AwsSession *session.Session } Order interface { // 下单 @@ -44,6 +49,8 @@ type ( List(ctx context.Context, in *ListReq) (res *ListRes, err error) // 详情 Detail(ctx context.Context, in *DetailReq) (res *DetailRes, err error) + // 发票 + Invoice(ctx context.Context, in *InvoiceReq) (res *InvoiceRes, err error) // 支付成功 PaymentSuccessful(ctx context.Context, in *PaymentSuccessfulReq) (res *PaymentSuccessfulRes, err error) // 关闭 @@ -65,9 +72,14 @@ type ( } OrderAddress struct { - Address string `json:"address"` // 详细地址 - Mobile string `json:"mobile"` // 手机 - Name string `json:"name"` // 姓名 + Street string `json:"street"` // 详细地址 + City string `json:"city"` // 城市 + FirstName string `json:"first_name"` // 姓 + LastName string `json:"last_name"` // 名 + Mobile string `json:"mobile"` // 手机 + State string `json:"state"` // 州 + Suite string `json:"suite"` // 房号 + ZipCode string `json:"zip_code"` // 邮编号码 } OrderPay struct { ClientSecret string `json:"client_secret"` // 支付方--秘钥 @@ -85,6 +97,16 @@ type ( Amount int64 `json:"amount"` // 金额 Label string `json:"label"` // 标签 } + /* 发票 */ + InvoiceReq struct { + UserId int64 `json:"user_id"` + OrderSn string `json:"order_sn"` + } + InvoiceRes struct { + ErrorCode basic.StatusResponse + InvoiceUrls []string `json:"invoice_urls"` + } + /* 发票 */ /* 删除订单 */ DeleteReq struct { @@ -210,6 +232,292 @@ type ( /* 列表 */ ) +// 订单发票 +func (d *defaultOrder) Invoice(ctx context.Context, in *InvoiceReq) (res *InvoiceRes, err error) { + var errorCode basic.StatusResponse + var orderInfo gmodel.FsOrder + var receiptSnsResources []string + var receiptSnsDeposit string + var receiptSnsFinal string + var invoiceUrls []string + + var orderTradeDeposit gmodel.FsOrderTrade + var orderTradeFinal gmodel.FsOrderTrade + model := d.MysqlConn.Where("is_del = ?", 0) + if in.UserId != 0 { + model = model.Where("user_id = ?", in.UserId) + } + if in.OrderSn != "" { + model = model.Where("order_sn = ?", in.OrderSn) + } + result := model.Take(&orderInfo) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound + } else { + errorCode = *basic.CodeServiceErr + } + logc.Errorf(ctx, "order invoice detail failed, err: %v", err) + return &InvoiceRes{ + ErrorCode: errorCode, + }, result.Error + } + + if *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_PAIDDEPOSIT) || *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_PAIDDREMAINING) { + // 查询支付账单 + var orderTradeList []gmodel.FsOrderTrade + + model1 := d.MysqlConn + if in.OrderSn != "" { + model1 = model1.Where("order_sn = ?", in.OrderSn) + } + result1 := model1.Find(&orderTradeList) + if result1.Error != nil { + if errors.Is(result1.Error, gorm.ErrRecordNotFound) { + errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound + } else { + errorCode = *basic.CodeServiceErr + } + logc.Errorf(ctx, "order invoice trade failed, err: %v", err) + return &InvoiceRes{ + ErrorCode: errorCode, + }, result1.Error + } + if len(orderTradeList) > 0 { + for _, orderTrade := range orderTradeList { + receiptSnsResources = append(receiptSnsResources, hash.JsonHashKey(*orderTrade.ReceiptSn)) + if *orderTrade.PayStage == 1 { + receiptSnsDeposit = *orderTrade.ReceiptSn + orderTradeDeposit = orderTrade + } + if *orderTrade.PayStage == 2 { + receiptSnsFinal = *orderTrade.ReceiptSn + orderTradeFinal = orderTrade + } + } + // 查询支付账单 + var resourceList []gmodel.FsResource + result2 := d.MysqlConn.Where("resource_id in ?", receiptSnsResources).Find(&resourceList) + if result2.Error != nil { + errorCode = *basic.CodeServiceErr + logc.Errorf(ctx, "order invoice esource failed, err: %v", err) + return &InvoiceRes{ + ErrorCode: errorCode, + }, result1.Error + } + resourceListLen := len(resourceList) + for _, resource := range resourceList { + invoiceUrls = append(invoiceUrls, *resource.ResourceUrl) + } + if *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_PAIDDEPOSIT) { + if resourceListLen == 1 { + return &InvoiceRes{ + ErrorCode: errorCode, + InvoiceUrls: invoiceUrls, + }, nil + } + if resourceListLen == 0 { + receiptSnsFinal = "" + } + } + if *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_PAIDDREMAINING) { + if resourceListLen == 2 { + return &InvoiceRes{ + ErrorCode: errorCode, + InvoiceUrls: invoiceUrls, + }, nil + } + if resourceListLen == 1 { + receiptSnsDeposit = "" + } + } + } else { + errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound + return &InvoiceRes{ + ErrorCode: errorCode, + }, errors.New("get order invoice failed, not found") + } + } else { + err = errors.New("get order invoice failed, pay status is illegality") + errorCode = *basic.CodeErrOrderInvoiceStatusIllegality + return &InvoiceRes{ + ErrorCode: errorCode, + }, err + } + + ress, err := d.OrderDetailHandler(ctx, &orderInfo, 1) + if err != nil { + logc.Errorf(ctx, "order invoice detail handler failed, err: %v", err) + errorCode = *basic.CodeServiceErr + return &InvoiceRes{ + ErrorCode: errorCode, + }, err + } else { + var model001 = constants.INVOICE_TEMPLATE_01 + var model002 string + var model003 string + var model004 string + var model005 string + var model006 = constants.INVOICE_TEMPLATE_06 + // 生成收据发票--首款 + ctimeDate := orderInfo.Ctime.Format("2006/01/02") + var name string + var city string + var street string + var state string + if ress.OrderDetail.DeliveryAddress != nil { + name = fmt.Sprintf("%s %s", ress.OrderDetail.DeliveryAddress.FirstName, ress.OrderDetail.DeliveryAddress.LastName) + street = ress.OrderDetail.DeliveryAddress.Street + city = ress.OrderDetail.DeliveryAddress.City + state = ress.OrderDetail.DeliveryAddress.State + } + + var products string + for _, orderProduct := range ress.OrderDetail.OrderProduct { + var model00301 = constants.INVOICE_TEMPLATE_0301 + var price = fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(orderProduct.ItemPrice.Current.CurrentCurrency)], orderProduct.ItemPrice.Current.CurrentAmount.(string)) + var priceTotal = fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(orderProduct.TotalPrice.Current.CurrentCurrency)], orderProduct.TotalPrice.Current.CurrentAmount.(string)) + var productsInfo = fmt.Sprintf(model00301, orderProduct.ProductName, price, orderProduct.PurchaseQuantity.Current, priceTotal) + products = products + productsInfo + } + model003 = fmt.Sprintf(constants.INVOICE_TEMPLATE_03, "", products) + + var subtotal = fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Subtotal.Current.CurrentCurrency)], ress.OrderDetail.OrderAmount.Subtotal.Current.CurrentAmount.(string)) + var taxStr = "0.00" + if ress.OrderDetail.OrderAmount.Tax.Current.CurrentAmount != nil { + taxStr = ress.OrderDetail.OrderAmount.Tax.Current.CurrentAmount.(string) + } + var taxCurrency string = constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Tax.Current.CurrentCurrency)] + if taxCurrency == "" { + taxCurrency = constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Total.Current.CurrentCurrency)] + } + var tax = fmt.Sprintf("%s%s", taxCurrency, taxStr) + var total = fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Total.Current.CurrentCurrency)], ress.OrderDetail.OrderAmount.Total.Current.CurrentAmount.(string)) + + if receiptSnsDeposit != "" { + v1 := receiptSnsDeposit + v2 := name + v3 := ctimeDate + v4 := street + v5 := city + v6 := state + model002 = fmt.Sprintf(constants.INVOICE_TEMPLATE_02, "", v1, v2, v3, v4, v5, v6) + + v7 := "Deposit Requested" + v8 := fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Deposit.PayAmount.Current.CurrentCurrency)], ress.OrderDetail.OrderAmount.Deposit.PayAmount.Current.CurrentAmount.(string)) + v9 := "Deposit Due" + v10 := v8 + model004 = fmt.Sprintf(constants.INVOICE_TEMPLATE_04, "", subtotal, tax, total, v7, v8, v9, v10) + + cardSn := "****" + *orderTradeDeposit.CardSn + model005 = fmt.Sprintf(constants.INVOICE_TEMPLATE_05, "", *orderTradeDeposit.CardBrand, cardSn) + + var content = model001 + model002 + model003 + model004 + model005 + model006 + + base64, err := pdf.HtmlToPdfBase64(content, "html") + if err != nil { + logc.Errorf(ctx, "order invoice HtmlToPdfBase64 failed, err: %v", err) + errorCode = *basic.CodeServiceErr + return &InvoiceRes{ + ErrorCode: errorCode, + }, err + } + // 根据hash 查询数据资源 + var resourceId string = hash.JsonHashKey(receiptSnsDeposit) + + // 上传文件 + var upload = file.Upload{ + Ctx: ctx, + MysqlConn: d.MysqlConn, + AwsSession: d.AwsSession, + } + uploadRes, err := upload.UploadFileByBase64(&file.UploadBaseReq{ + FileHash: resourceId, + FileData: "data:application/pdf;base64," + base64, + UploadBucket: 1, + ApiType: 2, + UserId: *orderInfo.UserId, + GuestId: 0, + Source: "order_invoice", + Refresh: 1, + }) + if err != nil { + if err != nil { + logc.Errorf(ctx, "order invoice UploadFileByBase64 failed, err: %v", err) + errorCode = *basic.CodeServiceErr + return &InvoiceRes{ + ErrorCode: errorCode, + }, err + } + } + invoiceUrls = append(invoiceUrls, uploadRes.ResourceUrl) + } + + // 生成收据发票--尾款 + if receiptSnsFinal != "" { + v1 := receiptSnsFinal + v2 := name + v3 := ctimeDate + v4 := street + v5 := city + v6 := state + model002 = fmt.Sprintf(constants.INVOICE_TEMPLATE_02, "", v1, v2, v3, v4, v5, v6) + + v7 := "Balance Requested" + v8 := fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.RemainingBalance.PayAmount.Current.CurrentCurrency)], ress.OrderDetail.OrderAmount.RemainingBalance.PayAmount.Current.CurrentAmount.(string)) + v9 := "Balance Due" + v10 := v8 + model004 = fmt.Sprintf(constants.INVOICE_TEMPLATE_04, "", subtotal, tax, total, v7, v8, v9, v10) + + cardSn := "****" + *orderTradeFinal.CardSn + model005 = fmt.Sprintf(constants.INVOICE_TEMPLATE_05, "", *orderTradeDeposit.CardBrand, cardSn) + var content = model001 + model002 + model003 + model004 + model005 + model006 + base64, err := pdf.HtmlToPdfBase64(content, "html") + if err != nil { + logc.Errorf(ctx, "order invoice HtmlToPdfBase64 failed, err: %v", err) + errorCode = *basic.CodeServiceErr + return &InvoiceRes{ + ErrorCode: errorCode, + }, err + } + // 根据hash 查询数据资源 + var resourceId string = hash.JsonHashKey(receiptSnsDeposit) + + // 上传文件 + var upload = file.Upload{ + Ctx: ctx, + MysqlConn: d.MysqlConn, + AwsSession: d.AwsSession, + } + uploadRes, err := upload.UploadFileByBase64(&file.UploadBaseReq{ + FileHash: resourceId, + FileData: "data:application/pdf;base64," + base64, + UploadBucket: 1, + ApiType: 2, + UserId: *orderInfo.UserId, + GuestId: 0, + Source: "order_invoice", + Refresh: 1, + }) + if err != nil { + if err != nil { + logc.Errorf(ctx, "order invoice UploadFileByBase64 failed, err: %v", err) + errorCode = *basic.CodeServiceErr + return &InvoiceRes{ + ErrorCode: errorCode, + }, err + } + } + invoiceUrls = append(invoiceUrls, uploadRes.ResourceUrl) + } + + return &InvoiceRes{ + ErrorCode: errorCode, + InvoiceUrls: invoiceUrls, + }, nil + } +} + // 订单删除 func (d *defaultOrder) Delete(ctx context.Context, in *DeleteReq) (res *DeleteRes, err error) { var errorCode basic.StatusResponse @@ -626,6 +934,7 @@ func (d *defaultOrder) PaymentSuccessful(ctx context.Context, in *PaymentSuccess } // 新增交易信息 + receiptSn := order.GenerateReceiptNumber() tx.Create(&gmodel.FsOrderTrade{ UserId: orderInfo.UserId, OrderSn: &orderSn, @@ -642,6 +951,7 @@ func (d *defaultOrder) PaymentSuccessful(ctx context.Context, in *PaymentSuccess Ctime: &ntime, Utime: &ntime, PayTitle: &payTitle, + ReceiptSn: &receiptSn, }) // 更新数据库 @@ -818,9 +1128,14 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL && in.DeliveryAddress != nil { orderAddress = &gmodel.OrderAddress{ - Name: in.DeliveryAddress.Name, - Mobile: in.DeliveryAddress.Mobile, - Address: in.DeliveryAddress.Address, + Street: in.DeliveryAddress.Street, + City: in.DeliveryAddress.City, + FirstName: in.DeliveryAddress.FirstName, + LastName: in.DeliveryAddress.LastName, + Mobile: in.DeliveryAddress.Mobile, + State: in.DeliveryAddress.State, + Suite: in.DeliveryAddress.Suite, + ZipCode: in.DeliveryAddress.ZipCode, } orderAddressByte, err = json.Marshal(orderAddress) if err != nil { @@ -1101,8 +1416,14 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe // 直邮 if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL { orderAddress = &gmodel.OrderAddress{ - Mobile: in.DeliveryAddress.Mobile, - Name: in.DeliveryAddress.Name, + Street: in.DeliveryAddress.Street, + City: in.DeliveryAddress.City, + FirstName: in.DeliveryAddress.FirstName, + LastName: in.DeliveryAddress.LastName, + Mobile: in.DeliveryAddress.Mobile, + State: in.DeliveryAddress.State, + Suite: in.DeliveryAddress.Suite, + ZipCode: in.DeliveryAddress.ZipCode, } } // 预计交付时间 diff --git a/utils/basic/basic.go b/utils/basic/basic.go index 3621d6bb..4121aa1b 100644 --- a/utils/basic/basic.go +++ b/utils/basic/basic.go @@ -113,6 +113,7 @@ var ( CodeErrOrderCreatePrePaymentPaid = &StatusResponse{5309, "create payment failed, order is paid"} CodeErrOrderCreatePrePaymentTimeout = &StatusResponse{5310, "create payment failed, timeout"} CodeErrOrderDeleteStatusIllegality = &StatusResponse{5311, "delete order failed, status is illegality"} + CodeErrOrderInvoiceStatusIllegality = &StatusResponse{5312, "get order invoice failed, pay status is illegality"} ) type Response struct { diff --git a/utils/order/order.go b/utils/order/order.go index 7543e92b..1ce86761 100644 --- a/utils/order/order.go +++ b/utils/order/order.go @@ -125,10 +125,15 @@ func GetPurchaseQuantity(req *gmodel.PurchaseQuantity) gmodel.PurchaseQuantity { func GenerateOrderNumber() string { t := time.Now() orderNumber := fmt.Sprintf("%d%02d%02d%08d", t.Year(), t.Month(), t.Day(), t.UnixNano()%100000000) - fmt.Println(orderNumber) return orderNumber } +// 生成收据编号 +func GenerateReceiptNumber() string { + t := time.Now() + return fmt.Sprintf("%02d%02d%02d%08d", t.Year()%100, t.Month(), t.Day(), t.UnixNano()%100000000) +} + // 初始化订单状态--链路 func GenerateOrderStatusLink(deliveryMethod int64, noTime time.Time, expectedTime time.Time) []gmodel.OrderStatus { var list []gmodel.OrderStatus diff --git a/utils/order/order_invoice.go b/utils/order/order_invoice.go new file mode 100644 index 00000000..375dad9c --- /dev/null +++ b/utils/order/order_invoice.go @@ -0,0 +1,5 @@ +package order + +func GetOrderInvoice() string { + return "" +}