flamingo.me/flamingo-commerce/v3@v3.11.0/cart/infrastructure/placeorder/logger.go (about)

     1  package logger
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"path"
    10  	"time"
    11  
    12  	cartDomain "flamingo.me/flamingo-commerce/v3/cart/domain/cart"
    13  	"flamingo.me/flamingo-commerce/v3/cart/domain/placeorder"
    14  	"flamingo.me/flamingo/v3/core/auth"
    15  	"flamingo.me/flamingo/v3/framework/flamingo"
    16  	"golang.org/x/mod/modfile"
    17  )
    18  
    19  type (
    20  	// PlaceOrderLoggerAdapter provides an implementation of the Service as email adapter
    21  	PlaceOrderLoggerAdapter struct {
    22  		useFlamingoLog bool
    23  		logAsFile      bool
    24  		logDirectory   string
    25  		logger         flamingo.Logger
    26  	}
    27  )
    28  
    29  var (
    30  	_ placeorder.Service = new(PlaceOrderLoggerAdapter)
    31  )
    32  
    33  // Inject dependencies
    34  func (e *PlaceOrderLoggerAdapter) Inject(logger flamingo.Logger,
    35  	config *struct {
    36  		UseFlamingoLog bool   `inject:"config:commerce.cart.placeOrderLogger.useFlamingoLog,optional"`
    37  		LogAsFile      bool   `inject:"config:commerce.cart.placeOrderLogger.logAsFile,optional"`
    38  		LogDirectory   string `inject:"config:commerce.cart.placeOrderLogger.logDirectory,optional"`
    39  	}) {
    40  	e.logger = logger.WithField("module", "cart").WithField("category", "emailAdapter")
    41  	if config != nil {
    42  		e.useFlamingoLog = config.UseFlamingoLog
    43  		e.logAsFile = config.LogAsFile
    44  		e.logDirectory = config.LogDirectory
    45  	}
    46  }
    47  
    48  // PlaceGuestCart places a guest cart as order email
    49  func (e *PlaceOrderLoggerAdapter) PlaceGuestCart(ctx context.Context, cart *cartDomain.Cart, payment *placeorder.Payment) (placeorder.PlacedOrderInfos, error) {
    50  	return e.placeCart(cart, payment)
    51  }
    52  
    53  // PlaceCustomerCart places a customer cart as order email
    54  func (e *PlaceOrderLoggerAdapter) PlaceCustomerCart(ctx context.Context, auth auth.Identity, cart *cartDomain.Cart, payment *placeorder.Payment) (placeorder.PlacedOrderInfos, error) {
    55  	return e.placeCart(cart, payment)
    56  }
    57  
    58  // placeCart
    59  func (e *PlaceOrderLoggerAdapter) placeCart(cart *cartDomain.Cart, payment *placeorder.Payment) (placeorder.PlacedOrderInfos, error) {
    60  	err := e.checkPayment(cart, payment)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	err = e.logOrder(cart, payment)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	var placedOrders placeorder.PlacedOrderInfos
    69  	for _, del := range cart.Deliveries {
    70  		placedOrders = append(placedOrders, placeorder.PlacedOrderInfo{
    71  			OrderNumber:  cart.ID,
    72  			DeliveryCode: del.DeliveryInfo.Code,
    73  		})
    74  	}
    75  
    76  	return placedOrders, nil
    77  }
    78  
    79  // checkPayment
    80  func (e *PlaceOrderLoggerAdapter) checkPayment(cart *cartDomain.Cart, payment *placeorder.Payment) error {
    81  	if payment == nil && cart.GrandTotal.IsPositive() {
    82  		return errors.New("no valid payment given")
    83  	}
    84  	if cart.GrandTotal.IsPositive() {
    85  		totalPrice, err := payment.TotalValue()
    86  		if err != nil {
    87  			return err
    88  		}
    89  		if !totalPrice.Equal(cart.GrandTotal) {
    90  			return errors.New("payment total does not match with grandtotal")
    91  		}
    92  	}
    93  	return nil
    94  }
    95  
    96  // logOrder
    97  func (e *PlaceOrderLoggerAdapter) logOrder(cart *cartDomain.Cart, payment *placeorder.Payment) error {
    98  	if e.useFlamingoLog {
    99  		e.logger.WithField("placeorder", cart.ID).WithField("cart", cart).Info("Order placed and logged")
   100  	}
   101  	if e.logAsFile && e.logDirectory != "" {
   102  		if !modfile.IsDirectoryPath(e.logDirectory) {
   103  			return fmt.Errorf("%v is not a valid directory path", e.logDirectory)
   104  		}
   105  		// Create folder if not exist
   106  		if _, err := os.Stat(e.logDirectory); os.IsNotExist(err) {
   107  			err = os.MkdirAll(e.logDirectory, os.ModePerm)
   108  			if err != nil {
   109  				e.logger.Error(err)
   110  				return err
   111  			}
   112  		}
   113  		type order struct {
   114  			Cart    cartDomain.Cart
   115  			Payment placeorder.Payment
   116  		}
   117  		content, err := json.Marshal(order{
   118  			Cart:    *cart,
   119  			Payment: *payment,
   120  		})
   121  		if err != nil {
   122  			e.logger.Error(err)
   123  			return err
   124  		}
   125  		fileName := fmt.Sprintf("order-%v-%v.json", time.Now().Format(time.RFC3339), cart.ID)
   126  		err = os.WriteFile(path.Join(e.logDirectory, fileName), []byte(content), os.ModePerm)
   127  		if err != nil {
   128  			e.logger.WithField("placeorder", cart.ID).Error(err)
   129  		}
   130  		e.logger.WithField("placeorder", cart.ID).WithField("cart", cart).Info("Order placed")
   131  	}
   132  	return nil
   133  }
   134  
   135  // ReserveOrderID returns the reserved order id
   136  func (e *PlaceOrderLoggerAdapter) ReserveOrderID(ctx context.Context, cart *cartDomain.Cart) (string, error) {
   137  	return cart.ID, nil
   138  }
   139  
   140  // CancelGuestOrder cancels a guest order
   141  func (e *PlaceOrderLoggerAdapter) CancelGuestOrder(ctx context.Context, orderInfos placeorder.PlacedOrderInfos) error {
   142  	// since we don't actual place orders we just return nil here
   143  	return nil
   144  }
   145  
   146  // CancelCustomerOrder cancels a customer order
   147  func (e *PlaceOrderLoggerAdapter) CancelCustomerOrder(ctx context.Context, orderInfos placeorder.PlacedOrderInfos, auth auth.Identity) error {
   148  	// since we don't actual place orders we just return nil here
   149  	return nil
   150  }