2023-10-08 15:59:42 +07:00
package order
import (
2024-06-05 00:24:53 +07:00
"database/sql"
2024-06-04 02:59:31 +07:00
"encoding/json"
"errors"
2024-06-05 00:24:53 +07:00
"fmt"
2024-08-13 23:09:05 +07:00
errors2 "furtuna-be/internal/common/errors"
2023-10-08 15:59:42 +07:00
"furtuna-be/internal/common/logger"
2024-07-26 22:32:24 +07:00
"furtuna-be/internal/common/mycontext"
2024-06-04 02:59:31 +07:00
order2 "furtuna-be/internal/constants/order"
2023-10-08 15:59:42 +07:00
"furtuna-be/internal/entity"
"furtuna-be/internal/repository"
2024-06-04 02:59:31 +07:00
"furtuna-be/internal/utils/generator"
2023-10-08 15:59:42 +07:00
"go.uber.org/zap"
2024-06-04 02:59:31 +07:00
"golang.org/x/net/context"
"gorm.io/gorm"
"strconv"
"time"
2023-10-08 15:59:42 +07:00
)
2024-08-09 10:02:05 +07:00
type Config interface {
2024-08-21 22:48:14 +07:00
GetOrderFee ( source string ) float64
2024-08-09 10:02:05 +07:00
}
2023-10-08 15:59:42 +07:00
type OrderService struct {
2024-06-05 00:24:53 +07:00
repo repository . Order
crypt repository . Crypto
product repository . Product
midtrans repository . Midtrans
payment repository . Payment
txmanager repository . TransactionManager
wallet repository . WalletRepository
2024-08-09 10:02:05 +07:00
cfg Config
2023-10-08 15:59:42 +07:00
}
2024-06-05 00:24:53 +07:00
func NewOrderService (
repo repository . Order ,
product repository . Product , crypt repository . Crypto ,
midtrans repository . Midtrans , payment repository . Payment ,
txmanager repository . TransactionManager ,
2024-08-09 10:02:05 +07:00
wallet repository . WalletRepository , cfg Config ) * OrderService {
2023-10-08 15:59:42 +07:00
return & OrderService {
2024-06-05 00:24:53 +07:00
repo : repo ,
product : product ,
crypt : crypt ,
midtrans : midtrans ,
payment : payment ,
txmanager : txmanager ,
wallet : wallet ,
2024-08-09 10:02:05 +07:00
cfg : cfg ,
2023-10-08 15:59:42 +07:00
}
}
2024-07-30 22:02:36 +07:00
func ( s * OrderService ) CreateOrder ( ctx mycontext . Context , req * entity . OrderRequest ) ( * entity . OrderResponse , error ) {
2024-08-21 22:48:14 +07:00
productIDs := [ ] int64 { }
for _ , item := range req . OrderItems {
if item . Quantity != 0 {
productIDs = append ( productIDs , item . ProductID )
}
}
if len ( productIDs ) < 1 {
return nil , errors2 . ErrorBadRequest
2024-06-04 02:59:31 +07:00
}
2023-10-08 15:59:42 +07:00
2024-06-04 02:59:31 +07:00
products , err := s . product . GetProductsByIDs ( ctx , productIDs , req . PartnerID )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when getting products by IDs" , zap . Error ( err ) )
return nil , err
2023-10-08 15:59:42 +07:00
}
2024-08-18 12:38:29 +07:00
var siteID int64
2024-06-04 02:59:31 +07:00
productMap := make ( map [ int64 ] * entity . ProductDB )
for _ , product := range products {
productMap [ product . ID ] = product
2024-08-18 12:38:29 +07:00
siteID = product . SiteID
2024-06-04 02:59:31 +07:00
}
2023-10-08 15:59:42 +07:00
2024-06-04 02:59:31 +07:00
totalAmount := 0.0
for _ , item := range req . OrderItems {
product , ok := productMap [ item . ProductID ]
if ! ok {
logger . ContextLogger ( ctx ) . Error ( "product not found" , zap . Int64 ( "productID" , item . ProductID ) )
return nil , errors . New ( "product not found" )
}
totalAmount += product . Price * float64 ( item . Quantity )
}
2023-10-08 15:59:42 +07:00
2024-08-15 22:17:28 +07:00
parsedTime , err := time . Parse ( "2006-01-02" , req . VisitDate )
if err != nil {
fmt . Println ( "Error parsing date:" , err )
2024-08-16 17:34:53 +07:00
return nil , errors . New ( "visit date not defined" )
2024-08-15 22:17:28 +07:00
}
2024-06-04 02:59:31 +07:00
order := & entity . Order {
2024-08-18 12:38:29 +07:00
PartnerID : req . PartnerID ,
RefID : generator . GenerateUUID ( ) ,
Status : order2 . New . String ( ) ,
Amount : totalAmount ,
2024-08-21 22:48:14 +07:00
Total : totalAmount + s . cfg . GetOrderFee ( req . Source ) ,
Fee : s . cfg . GetOrderFee ( req . Source ) ,
2024-08-18 12:38:29 +07:00
PaymentType : req . PaymentMethod ,
SiteID : & siteID ,
CreatedBy : req . CreatedBy ,
OrderItems : [ ] entity . OrderItem { } ,
Source : req . Source ,
VisitDate : parsedTime ,
TicketStatus : "UNUSED" ,
2023-10-08 15:59:42 +07:00
}
2024-06-04 02:59:31 +07:00
for _ , item := range req . OrderItems {
order . OrderItems = append ( order . OrderItems , entity . OrderItem {
ItemID : item . ProductID ,
ItemType : productMap [ item . ProductID ] . Type ,
Price : productMap [ item . ProductID ] . Price ,
Quantity : item . Quantity ,
CreatedBy : req . CreatedBy ,
2024-06-05 00:24:53 +07:00
Product : productMap [ item . ProductID ] . ToProduct ( ) ,
2024-06-04 02:59:31 +07:00
} )
}
2023-10-08 15:59:42 +07:00
2024-06-04 02:59:31 +07:00
order , err = s . repo . Create ( ctx , order )
2023-10-08 15:59:42 +07:00
if err != nil {
2024-06-04 02:59:31 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when creating order" , zap . Error ( err ) )
2023-10-08 15:59:42 +07:00
return nil , err
}
2024-06-04 02:59:31 +07:00
token , err := s . crypt . GenerateJWTOrder ( order )
2023-10-08 15:59:42 +07:00
if err != nil {
2024-06-04 02:59:31 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when create token" , zap . Error ( err ) )
return nil , err
2023-10-08 15:59:42 +07:00
}
2024-08-21 22:56:53 +07:00
order , err = s . repo . FindByID ( ctx , int64 ( order . Total ) )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when creating order" , zap . Error ( err ) )
return nil , err
}
2024-06-04 02:59:31 +07:00
return & entity . OrderResponse {
Order : order ,
Token : token ,
} , nil
2023-10-08 15:59:42 +07:00
}
2024-08-13 23:09:05 +07:00
func ( s * OrderService ) CheckInInquiry ( ctx mycontext . Context , qrCode string , partnerID * int64 ) ( * entity . CheckinResponse , error ) {
order , err := s . repo . FindByQRCode ( ctx , qrCode )
if err != nil {
2024-08-14 00:10:53 +07:00
if errors . Is ( err , gorm . ErrRecordNotFound ) {
return nil , errors2 . NewErrorMessage ( errors2 . ErrorInvalidRequest , "Not Valid QR Code" )
}
2024-08-13 23:09:05 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when getting order by QR code" , zap . Error ( err ) )
return nil , err
}
if order . PartnerID != * partnerID {
return nil , errors2 . ErrorBadRequest
}
2024-08-13 23:53:01 +07:00
if order . Status != "PAID" {
return nil , errors2 . ErrorInvalidRequest
}
2024-08-13 23:09:05 +07:00
if order . TicketStatus == "USED" {
return nil , errors2 . ErrorTicketInvalidOrAlreadyUsed
}
today := time . Now ( ) . Format ( "2006-01-02" )
visitDate := order . VisitDate . Format ( "2006-01-02" )
if visitDate != today {
return nil , errors2 . ErrorTicketInvalidOrAlreadyUsed
}
token , err := s . crypt . GenerateJWTOrder ( order )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when generate checkin token" , zap . Error ( err ) )
return nil , err
}
orderResponse := & entity . CheckinResponse {
Token : token ,
}
return orderResponse , nil
}
func ( s * OrderService ) CheckInExecute ( ctx mycontext . Context ,
token string , partnerID * int64 ) ( * entity . CheckinExecute , error ) {
pID , orderID , err := s . crypt . ValidateJWTOrder ( token )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when validating JWT order" , zap . Error ( err ) )
return nil , err
}
if pID != * partnerID {
return nil , errors2 . ErrorBadRequest
}
order , err := s . repo . FindByID ( ctx , orderID )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when getting order by ID" , zap . Error ( err ) )
return nil , err
}
resp := & entity . CheckinExecute {
Order : order ,
}
2024-08-13 23:53:01 +07:00
if order . TicketStatus != "UNUSED" {
2024-08-13 23:09:05 +07:00
return resp , nil
}
2024-08-13 23:53:01 +07:00
order . TicketStatus = "USED"
2024-08-13 23:09:05 +07:00
order , err = s . repo . Update ( ctx , order )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when updating order status" , zap . Error ( err ) )
return nil , err
}
return resp , nil
}
2024-06-04 02:59:31 +07:00
func ( s * OrderService ) Execute ( ctx context . Context , req * entity . OrderExecuteRequest ) ( * entity . ExecuteOrderResponse , error ) {
partnerID , orderID , err := s . crypt . ValidateJWTOrder ( req . Token )
2023-10-08 15:59:42 +07:00
if err != nil {
2024-06-04 02:59:31 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when validating JWT order" , zap . Error ( err ) )
return nil , err
2023-10-08 15:59:42 +07:00
}
2024-06-04 02:59:31 +07:00
order , err := s . repo . FindByID ( ctx , orderID )
2023-10-08 15:59:42 +07:00
if err != nil {
2024-06-04 02:59:31 +07:00
if errors . Is ( err , gorm . ErrRecordNotFound ) {
logger . ContextLogger ( ctx ) . Error ( "order not found" , zap . Int64 ( "orderID" , orderID ) )
return nil , errors . New ( "order not found" )
}
logger . ContextLogger ( ctx ) . Error ( "error when finding order by ID" , zap . Error ( err ) )
2023-10-08 15:59:42 +07:00
return nil , err
}
2024-06-04 02:59:31 +07:00
payment , err := s . payment . FindByOrderAndPartnerID ( ctx , orderID , partnerID )
if err != nil && ! errors . Is ( err , gorm . ErrRecordNotFound ) {
logger . ContextLogger ( ctx ) . Error ( "error getting payment data from db" , zap . Error ( err ) )
return nil , err
}
2023-10-08 15:59:42 +07:00
2024-06-04 02:59:31 +07:00
if payment != nil {
return s . createExecuteOrderResponse ( order , payment ) , nil
}
if order . PartnerID != partnerID {
logger . ContextLogger ( ctx ) . Error ( "partner ID mismatch" , zap . Int64 ( "orderID" , orderID ) , zap . Int64 ( "tokenPartnerID" , partnerID ) , zap . Int64 ( "orderPartnerID" , order . PartnerID ) )
return nil , errors . New ( "partner ID mismatch" )
}
if order . Status != "NEW" {
return nil , errors . New ( "invalid state" )
}
resp := & entity . ExecuteOrderResponse {
Order : order ,
}
if order . PaymentType != "CASH" {
2024-08-06 16:21:55 +07:00
if order . PaymentType == "QRIS" {
paymentResponse , err := s . processQRPayment ( ctx , order , partnerID , req . CreatedBy )
if err != nil {
return nil , err
}
resp . QRCode = paymentResponse . QrCodeUrl
} else {
paymentResponse , err := s . processNonCashPayment ( ctx , order , partnerID , req . CreatedBy )
if err != nil {
return nil , err
}
resp . PaymentToken = paymentResponse . Token
resp . RedirectURL = paymentResponse . RedirectURL
2024-06-04 02:59:31 +07:00
}
}
order . SetExecutePaymentStatus ( )
order , err = s . repo . Update ( ctx , order )
2023-10-08 15:59:42 +07:00
if err != nil {
2024-06-04 02:59:31 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when updating order status" , zap . Error ( err ) )
2023-10-08 15:59:42 +07:00
return nil , err
}
2024-06-04 02:59:31 +07:00
return resp , nil
2023-10-08 15:59:42 +07:00
}
2024-06-04 02:59:31 +07:00
func ( s * OrderService ) createExecuteOrderResponse ( order * entity . Order , payment * entity . Payment ) * entity . ExecuteOrderResponse {
var metadata map [ string ] string
if err := json . Unmarshal ( payment . RequestMetadata , & metadata ) ; err != nil {
logger . ContextLogger ( context . Background ( ) ) . Error ( "error unmarshaling request metadata" , zap . Error ( err ) )
return & entity . ExecuteOrderResponse {
Order : order ,
}
}
return & entity . ExecuteOrderResponse {
Order : order ,
PaymentToken : metadata [ "payment_token" ] ,
RedirectURL : metadata [ "payment_redirect_url" ] ,
}
}
func ( s * OrderService ) processNonCashPayment ( ctx context . Context , order * entity . Order , partnerID , createdBy int64 ) ( * entity . MidtransResponse , error ) {
paymentRequest := entity . MidtransRequest {
PaymentReferenceID : generator . GenerateUUIDV4 ( ) ,
TotalAmount : int64 ( order . Amount ) ,
OrderItems : order . OrderItems ,
2024-08-04 01:14:59 +07:00
PaymentMethod : order . PaymentType ,
2024-06-04 02:59:31 +07:00
}
paymentResponse , err := s . midtrans . CreatePayment ( paymentRequest )
2023-10-08 15:59:42 +07:00
if err != nil {
2024-06-04 02:59:31 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when creating payment" , zap . Error ( err ) )
2023-10-08 15:59:42 +07:00
return nil , err
}
2024-06-04 02:59:31 +07:00
requestMetadata , err := json . Marshal ( map [ string ] string {
"partner_id" : strconv . FormatInt ( partnerID , 10 ) ,
"created_by" : strconv . FormatInt ( createdBy , 10 ) ,
"payment_token" : paymentResponse . Token ,
"payment_redirect_url" : paymentResponse . RedirectURL ,
} )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when marshaling request metadata" , zap . Error ( err ) )
return nil , err
2023-10-08 15:59:42 +07:00
}
2024-06-04 02:59:31 +07:00
payment := & entity . Payment {
2024-06-05 00:24:53 +07:00
PartnerID : partnerID ,
OrderID : order . ID ,
2024-06-04 02:59:31 +07:00
ReferenceID : paymentRequest . PaymentReferenceID ,
2024-08-06 16:21:55 +07:00
Channel : "MIDTRANS" ,
PaymentType : order . PaymentType ,
Amount : order . Amount ,
State : "PENDING" ,
CreatedAt : time . Now ( ) ,
UpdatedAt : time . Now ( ) ,
RequestMetadata : requestMetadata ,
}
_ , err = s . payment . Create ( ctx , payment )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when creating payment record" , zap . Error ( err ) )
return nil , err
}
return paymentResponse , nil
}
func ( s * OrderService ) processQRPayment ( ctx context . Context , order * entity . Order , partnerID , createdBy int64 ) ( * entity . MidtransQrisResponse , error ) {
paymentRequest := entity . MidtransRequest {
PaymentReferenceID : generator . GenerateUUIDV4 ( ) ,
TotalAmount : int64 ( order . Amount ) ,
OrderItems : order . OrderItems ,
PaymentMethod : order . PaymentType ,
}
paymentResponse , err := s . midtrans . CreateQrisPayment ( paymentRequest )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when creating payment" , zap . Error ( err ) )
return nil , err
}
requestMetadata , err := json . Marshal ( map [ string ] string {
"partner_id" : strconv . FormatInt ( partnerID , 10 ) ,
"created_by" : strconv . FormatInt ( createdBy , 10 ) ,
"qr_code" : paymentResponse . QrCodeUrl ,
} )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when marshaling request metadata" , zap . Error ( err ) )
return nil , err
}
payment := & entity . Payment {
PartnerID : partnerID ,
OrderID : order . ID ,
ReferenceID : paymentRequest . PaymentReferenceID ,
Channel : "MIDTRANS" ,
2024-06-04 02:59:31 +07:00
PaymentType : order . PaymentType ,
Amount : order . Amount ,
2024-06-05 00:24:53 +07:00
State : "PENDING" ,
2024-06-04 02:59:31 +07:00
CreatedAt : time . Now ( ) ,
UpdatedAt : time . Now ( ) ,
RequestMetadata : requestMetadata ,
2023-10-08 15:59:42 +07:00
}
2024-06-04 02:59:31 +07:00
_ , err = s . payment . Create ( ctx , payment )
2023-10-08 15:59:42 +07:00
if err != nil {
2024-06-04 02:59:31 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when creating payment record" , zap . Error ( err ) )
2023-10-08 15:59:42 +07:00
return nil , err
}
2024-06-04 02:59:31 +07:00
return paymentResponse , nil
2023-10-08 15:59:42 +07:00
}
2024-06-05 00:24:53 +07:00
func ( s * OrderService ) ProcessCallback ( ctx context . Context , req * entity . CallbackRequest ) error {
tx , err := s . txmanager . Begin ( ctx , & sql . TxOptions { Isolation : sql . LevelSerializable } )
if err != nil {
return fmt . Errorf ( "failed to begin transaction: %w" , err )
}
defer tx . Rollback ( )
err = s . processPayment ( ctx , tx , req )
if err != nil {
return fmt . Errorf ( "failed to process payment: %w" , err )
}
return tx . Commit ( ) . Error
}
func ( s * OrderService ) processPayment ( ctx context . Context , tx * gorm . DB , req * entity . CallbackRequest ) error {
existingPayment , err := s . payment . FindByReferenceID ( ctx , tx , req . TransactionID )
if err != nil {
return fmt . Errorf ( "failed to retrieve payment: %w" , err )
}
existingPayment . State = updatePaymentState ( req . TransactionStatus )
_ , err = s . payment . UpdateWithTx ( ctx , tx , existingPayment )
if err != nil {
return fmt . Errorf ( "failed to update payment: %w" , err )
}
if err := s . updateOrderStatus ( ctx , tx , existingPayment . State , existingPayment . OrderID ) ; err != nil {
return fmt . Errorf ( "failed to update order status: %w" , err )
}
if existingPayment . State == "PAID" {
if err := s . updateWalletBalance ( ctx , tx , existingPayment . PartnerID , existingPayment . Amount ) ; err != nil {
return fmt . Errorf ( "failed to update wallet balance: %w" , err )
}
}
return nil
}
func updatePaymentState ( status string ) string {
switch status {
case "settlement" , "capture" :
return "PAID"
case "expire" , "deny" , "cancel" , "failure" :
return "EXPIRED"
default :
return status
}
}
func ( s * OrderService ) updateOrderStatus ( ctx context . Context , tx * gorm . DB , status string , orderID int64 ) error {
if status != "PENDING" {
return s . repo . SetOrderStatus ( ctx , tx , orderID , status )
}
return nil
}
func ( s * OrderService ) updateWalletBalance ( ctx context . Context , tx * gorm . DB , partnerID int64 , amount float64 ) error {
wallet , err := s . wallet . GetByPartnerID ( ctx , tx , partnerID )
if err != nil {
return fmt . Errorf ( "failed to get wallet: %w" , err )
}
wallet . Balance += amount
_ , err = s . wallet . Update ( ctx , tx , wallet )
return err
}
2024-07-26 11:37:22 +07:00
2024-07-27 16:47:33 +07:00
func ( s * OrderService ) GetAllHistoryOrders ( ctx mycontext . Context , req entity . OrderSearch ) ( [ ] * entity . HistoryOrder , int , error ) {
2024-07-26 22:32:24 +07:00
historyOrders , total , err := s . repo . GetAllHystoryOrders ( ctx , req )
2024-07-26 11:37:22 +07:00
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when get all history orders" , zap . Error ( err ) )
return nil , 0 , err
}
data := historyOrders . ToHistoryOrderList ( )
return data , total , nil
}
2024-07-27 16:47:33 +07:00
2024-08-13 23:09:05 +07:00
func ( s * OrderService ) CountSoldOfTicket ( ctx mycontext . Context , req entity . OrderSearch ) ( * entity . TicketSold , error ) {
2024-07-27 16:47:33 +07:00
ticket , err := s . repo . CountSoldOfTicket ( ctx , req )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when get all history orders" , zap . Error ( err ) )
return nil , err
}
data := ticket . ToTicketSold ( )
return data , nil
}
2024-08-13 23:09:05 +07:00
func ( s * OrderService ) GetDailySales ( ctx mycontext . Context , req entity . OrderSearch ) ( [ ] entity . ProductDailySales , error ) {
2024-08-02 02:27:57 +07:00
dailySales , err := s . repo . GetDailySalesMetrics ( ctx , req )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when get all history orders" , zap . Error ( err ) )
return nil , err
}
return dailySales , nil
}
2024-08-13 23:09:05 +07:00
func ( s * OrderService ) GetPaymentDistribution ( ctx mycontext . Context , req entity . OrderSearch ) ( [ ] entity . PaymentTypeDistribution , error ) {
2024-08-02 15:16:28 +07:00
paymentDistribution , err := s . repo . GetPaymentTypeDistribution ( ctx , req )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when get all history orders" , zap . Error ( err ) )
return nil , err
}
return paymentDistribution , nil
}
2024-08-13 23:09:05 +07:00
func ( s * OrderService ) SumAmount ( ctx mycontext . Context , req entity . OrderSearch ) ( * entity . Order , error ) {
2024-07-27 16:47:33 +07:00
amount , err := s . repo . SumAmount ( ctx , req )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when get amount cash orders" , zap . Error ( err ) )
return nil , err
}
data := amount . ToSumAmount ( )
return data , nil
2024-07-30 22:02:36 +07:00
}
2024-08-04 01:14:59 +07:00
2024-08-06 16:21:55 +07:00
func ( s * OrderService ) GetByID ( ctx mycontext . Context , id int64 , referenceID string ) ( * entity . Order , error ) {
if referenceID != "" {
payment , err := s . payment . FindByReferenceID ( ctx , nil , referenceID )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when getting payment by IDs" , zap . Error ( err ) )
return nil , err
}
id = payment . OrderID
}
2024-08-04 01:14:59 +07:00
order , err := s . repo . FindByID ( ctx , id )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when getting products by IDs" , zap . Error ( err ) )
return nil , err
}
2024-08-06 16:21:55 +07:00
if ctx . IsCasheer ( ) {
return order , nil
2024-08-04 01:14:59 +07:00
}
2024-08-06 16:21:55 +07:00
//if order.CreatedBy != ctx.RequestedBy() {
// return nil, errors2.NewError(errors2.ErrorBadRequest.ErrorType(), "order not found")
//}
2024-08-04 01:14:59 +07:00
return order , nil
}
2024-08-21 15:48:50 +07:00
func ( s * OrderService ) GetPrintDetail ( ctx mycontext . Context , id int64 ) ( * entity . OrderPrintDetail , error ) {
order , err := s . repo . FindPrintDetailByID ( ctx , id )
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when getting products by IDs" , zap . Error ( err ) )
return nil , err
}
return order , nil
}