250 lines
7.0 KiB
Go
Raw Normal View History

2025-03-08 00:35:23 +07:00
package order
import (
"enaklo-pos-be/internal/common/logger"
"enaklo-pos-be/internal/common/mycontext"
"enaklo-pos-be/internal/constants"
"enaklo-pos-be/internal/entity"
"fmt"
"go.uber.org/zap"
2025-06-06 14:48:09 +07:00
"time"
2025-03-08 00:35:23 +07:00
)
func (s *orderSvc) ExecuteOrderInquiry(ctx mycontext.Context,
2025-04-10 11:21:08 +07:00
token string, paymentMethod, paymentProvider string, inprogressOrderID int64) (*entity.OrderResponse, error) {
2025-03-08 00:35:23 +07:00
inquiry, err := s.validateInquiry(ctx, token)
if err != nil {
return nil, err
}
2025-04-05 11:28:06 +08:00
order := inquiry.ToOrder(paymentMethod, paymentProvider)
order.InProgressOrderID = inprogressOrderID
2025-03-08 00:35:23 +07:00
savedOrder, err := s.repo.Create(ctx, order)
if err != nil {
logger.ContextLogger(ctx).Error("failed to create order", zap.Error(err))
return nil, err
}
err = s.processPostOrderActions(ctx, savedOrder, inquiry.ID, paymentMethod)
if err != nil {
logger.ContextLogger(ctx).Warn("some post-order actions failed", zap.Error(err))
}
return &entity.OrderResponse{
Order: savedOrder,
}, nil
}
func (s *orderSvc) processPostOrderActions(
ctx mycontext.Context,
order *entity.Order,
inquiryID string,
paymentMethod string,
) error {
err := s.repo.UpdateInquiryStatus(ctx, inquiryID, constants.StatusExecuted)
if err != nil {
logger.ContextLogger(ctx).Error("error when updating inquiry status", zap.Error(err))
}
trx, err := s.createTransaction(ctx, order, paymentMethod)
if err != nil {
logger.ContextLogger(ctx).Error("error when creating transaction", zap.Error(err))
}
if order.CustomerID != nil && *order.CustomerID > 0 {
2025-06-06 14:48:09 +07:00
err = s.addCustomerVouchers(ctx, *order.CustomerID, int64(order.Total), trx.OrderID)
2025-03-08 00:35:23 +07:00
if err != nil {
logger.ContextLogger(ctx).Error("error when adding points", zap.Error(err))
}
}
return nil
}
func (s *orderSvc) createTransaction(ctx mycontext.Context, order *entity.Order, paymentMethod string) (*entity.Transaction, error) {
transaction := &entity.Transaction{
ID: constants.GenerateUUID(),
OrderID: order.ID,
Amount: order.Total,
PaymentMethod: paymentMethod,
Status: "SUCCESS",
CreatedAt: constants.TimeNow(),
PartnerID: order.PartnerID,
TransactionType: "TRANSACTION",
}
_, err := s.transaction.Create(ctx, transaction)
return transaction, err
}
2025-06-06 14:48:09 +07:00
func (s *orderSvc) addCustomerVouchers(ctx mycontext.Context, customerID int64, total int64, reference int64) error {
undians, err := s.voucherUndianRepo.GetActiveUndianEvents(ctx)
if err != nil {
return err
}
eligibleVoucher := []*entity.UndianVoucherDB{}
totalVouchersNeeded := 0
for _, v := range undians {
if total >= int64(v.MinimumPurchase) {
voucherCount := int(total / int64(v.MinimumPurchase))
totalVouchersNeeded += voucherCount
}
}
if totalVouchersNeeded == 0 {
return nil
}
startSequence, err := s.voucherUndianRepo.GetNextVoucherSequenceBatch(ctx, totalVouchersNeeded)
if err != nil {
return err
}
currentSequence := startSequence
for _, v := range undians {
if total >= int64(v.MinimumPurchase) {
voucherCount := int(total / int64(v.MinimumPurchase))
for i := 0; i < voucherCount; i++ {
voucherCode := s.generateVoucherCode(v.ID, reference, currentSequence)
voucher := &entity.UndianVoucherDB{
UndianEventID: v.ID,
CustomerID: customerID,
VoucherCode: voucherCode,
VoucherNumber: &i,
IsWinner: false,
CreatedAt: time.Now(),
}
eligibleVoucher = append(eligibleVoucher, voucher)
currentSequence++
}
}
}
return s.voucherUndianRepo.CreateUndianVouchers(ctx, eligibleVoucher)
}
func (s *orderSvc) generateVoucherCode(eventID int64, reference int64, sequence int64) string {
eventPart := eventID % 100 // Last 2 digits of event ID
sequencePart := sequence % 100000 // Last 5 digits of sequence
orderPart := reference % 1000 // Last 3 digits of order ID
return fmt.Sprintf("%02d%05d%03d", eventPart, sequencePart, orderPart)
2025-03-08 00:35:23 +07:00
}
func (s *orderSvc) sendTransactionReceipt(ctx mycontext.Context, order *entity.Order, transaction *entity.Transaction, paymentMethod string) error {
2025-05-06 15:21:12 +07:00
newPoint := int(order.Total / 50000)
if newPoint <= 0 {
return nil
}
2025-03-08 00:35:23 +07:00
if order.CustomerID == nil || *order.CustomerID == 0 {
return nil
}
2025-05-06 15:21:12 +07:00
customerPoint, err := s.customer.GetCustomerPoints(ctx, *order.CustomerID)
if err != nil {
return nil
}
2025-03-08 00:35:23 +07:00
customer, err := s.customer.GetCustomer(ctx, *order.CustomerID)
if err != nil {
logger.ContextLogger(ctx).Error("error getting customer details", zap.Error(err))
return err
}
branchName := "Bakso 343 Rawamangun"
var productIDs []int64
productIDMap := make(map[int64]bool)
for _, item := range order.OrderItems {
if item.ItemID > 0 && !productIDMap[item.ItemID] {
productIDs = append(productIDs, item.ItemID)
productIDMap[item.ItemID] = true
}
}
productMap := make(map[int64]*entity.Product)
if len(productIDs) > 0 {
products, err := s.product.GetProductsByIDs(ctx, productIDs, order.PartnerID)
if err != nil {
logger.ContextLogger(ctx).Error("error fetching products", zap.Error(err))
} else {
for _, product := range products {
productMap[product.ID] = product
}
}
}
var itemsData []map[string]string
for _, item := range order.OrderItems {
itemName := "Item"
if product, exists := productMap[item.ItemID]; exists {
itemName = product.Name
}
itemsData = append(itemsData, map[string]string{
"ItemName": itemName,
"Quantity": fmt.Sprintf("%d", item.Quantity),
"Price": fmt.Sprintf("Rp %s", formatCurrency(item.Price)),
})
}
transactionDate := transaction.CreatedAt.Format("02 January 2006 15:04")
2025-05-06 15:21:12 +07:00
viewTransactionLink := "https://web.enaklo.co.id"
2025-03-08 00:35:23 +07:00
emailData := map[string]interface{}{
"UserName": customer.Name,
2025-05-06 15:21:12 +07:00
"PointsName": "Point",
"PointsBalance": newPoint,
"NewPoints": newPoint,
"TotalPoints": customerPoint.TotalPoints,
"RedeemLink": "web.enaklo.co.id",
2025-03-08 00:35:23 +07:00
"BranchName": branchName,
"TransactionNumber": order.ID,
"TransactionDate": transactionDate,
"PaymentMethod": formatPaymentMethod(paymentMethod),
"Items": itemsData,
"TotalPayment": fmt.Sprintf("Rp %s", formatCurrency(order.Total)),
"ViewTransactionLink": viewTransactionLink,
2025-03-16 11:01:58 +08:00
"ExpiryDate": order.CreatedAt.Format("02 January 2006"),
2025-05-06 15:21:12 +07:00
"UndianDate": "17 Mei 2025",
"WebURL": "https://web.enaklo.co.id/undian",
2025-03-08 00:35:23 +07:00
}
return s.notification.SendEmailTransactional(ctx, entity.SendEmailNotificationParam{
Sender: "noreply@enaklo.co.id",
Recipient: customer.Email,
2025-03-16 11:01:58 +08:00
Subject: "Hore, kamu dapat poin!",
2025-03-15 15:51:18 +08:00
TemplateName: "monthly_points",
2025-03-16 23:42:42 +07:00
TemplatePath: "/templates/monthly_points.html",
2025-03-08 00:35:23 +07:00
Data: emailData,
})
}
func formatCurrency(amount float64) string {
return fmt.Sprintf("%.2f", amount)
}
func formatPaymentMethod(method string) string {
methodMap := map[string]string{
"CASH": "Tunai",
"QRIS": "QRIS",
"CARD": "Kartu Kredit/Debit",
}
if displayName, exists := methodMap[method]; exists {
return displayName
}
return method
}