import { Cart, CartRepository, Cashier, FflDealer, Line, PaymentUtils } from '@inmotion/swift-libs'; import { UserSettingsRepository } from '@inmotion/swift-libs/data/UserSettingsRepository'; import { CartModificationService } from '@inmotion/swift-libs/services/cart-modification.service'; import { AppSettingsService, AppSettingsServiceFactory, DiscountService, DiscountServiceFactory, FFL_SELECT_TYPES, FFLDealerRepository, IFactory, LineUtils, OrderStatusType, OrderUtils, PaymentMethodType, ProductRepository, RequestService, ShippingSettings, UrlBuilder, Validator } from '@whittaker/swift-libs'; import { IApplicationContext } from '@inmotion/core'; import { BaseCartCreationService } from './base-cart-creation.service'; import { CartBuilderInput, CartState, CartStatus } from './models.cart'; import { CartCreateUtils } from './cart-creation.utils'; export class CartCreationService extends BaseCartCreationService { constructor(protected _productRepo: ProductRepository, protected _cartModService: CartModificationService, protected _cartRepo: CartRepository, protected _urlBuilder: UrlBuilder, protected _requestService: RequestService, protected _userSettingsRepo: UserSettingsRepository, protected _appSettingsService: AppSettingsService, protected _discountService: DiscountService, protected _cartUtils: CartCreateUtils, protected _fflRepo: FFLDealerRepository,) { super( _productRepo, _cartModService, _cartRepo, _urlBuilder, _requestService, _userSettingsRepo, _appSettingsService, _discountService, _cartUtils ); } public defaultCart(): Cart { let cart = new Cart(); cart.Cashier = Cashier.ECOM_STORE; cart.Disposition.Value = OrderStatusType.OPEN.Name; cart.Lines = []; cart.Discount = null; cart.Summary.OccuredOn = new Date().toISOString(); cart.Summary.Total.Distribution.Amount = 0; cart.Summary.Total.Distribution.Discount = 0; cart.Summary.Total.Distribution.Gratuity = 0; cart.Summary.Total.Distribution.Shipping = 0; cart.Summary.Total.Distribution.SubTotal = 0; cart.Summary.Total.Distribution.Tax = 0; cart.Summary.Total.Distribution.Value = 0; cart.Payment = PaymentUtils.formatPaymentForCreditCard(cart.Payment); cart.Status.Disposition.Value = OrderStatusType.CREATED.Name; cart.Summary.PaymentMethod = PaymentMethodType.CREDIT_CARD.Id; cart.Payment.Method = PaymentMethodType.CREDIT_CARD.Id; cart.FFLType = FFL_SELECT_TYPES.SELECT; cart.Attributes.IsFFLRequired = false; cart.Attributes.IsShippingRequired = false; cart.Summary.Options.isShippingInsurance = true; delete cart.__i; return cart; } protected async buildState(cart: Cart): Promise { if (this._cartUtils.isGuest(OrderUtils.getUserEmail(cart))) { return this.buildGuestState(cart); } else { throw new Error('Not implemented'); } } protected async buildGuestState(cart: Cart): Promise { Validator.throwIfNil(cart, `Missing cart`); let state: CartState = new CartState(); state.cart = cart; state.status = await this.evaluateGuestStatus(cart); state.input = this.transformToCartBuilderInput(cart); return state; } protected async evaluateGuestStatus(cart: Cart): Promise { let status: CartStatus = new CartStatus(), shippingSettings: ShippingSettings; status.isGuest = true; status.totalItemQuantity = LineUtils.getTotalQuantity(cart.Lines); // shipping -------------------------------------------------------------------------------------------------------- shippingSettings = await this._appSettingsService.fetchShippingSettings().toPromise(); status.shippingInsuranceEnabled = shippingSettings.IsInsurable; status.isFreeShipping = shippingSettings.Free.Enabled && OrderUtils.getOrderTotal(cart) >= shippingSettings.Free.MinimumTotal; // shipping -------------------------------------------------------------------------------------------------------- // client-specific ------------------------------------------------------------------------------------------------- status.isEligibleForLayaway = false; // not available for guest checkout status.hasUnpaidOrders = false; status.hasFirearms = LineUtils.hasFirearmLines(cart.Lines); status.isLayaway = false; // client-specific ------------------------------------------------------------------------------------------------- return status; } protected transformToCartBuilderInput(cart: Cart, addEmptyLineIfNone: boolean = true): CartBuilderInput { let input = this._cartUtils.transformCommonCartBuilderInputProperties(cart, addEmptyLineIfNone); input = this.transformClientSpecificCartBuilderInputProperties(input, cart); return input; } protected transformClientSpecificCartBuilderInputProperties(input: CartBuilderInput, cart: Cart): CartBuilderInput { input.fflNumber = cart.FFL ? cart.FFL.FFLNumber : null; return input; } protected async setClientSpecificCartProperties(input: CartBuilderInput, cart: Cart): Promise { const cartFflNumber: string = cart.FFL ? cart.FFL.FFLNumber : null; if (input.fflNumber && input.fflNumber != cartFflNumber) { const ffl: FflDealer = await this._fflRepo.getOneAsync({ 'Payload.FFLNumber': input.fflNumber }); cart.FFL = ffl || null; } return cart; } protected async checkLayawayAvailability(userEmail: string, lines: Line[]): Promise { if (!userEmail) return false; // must contain only one product in cart, and that item must be a firearm if (LineUtils.getTotalQuantity(lines) != 1) return false; if (!LineUtils.hasFirearmLines(lines)) return false; // fetch available payment types... if !layaway return false // fetch unpaid orders => if any return false return false; } } export class CartCreationServiceFactory implements IFactory { constructor(protected appContext: IApplicationContext, protected _productRepo: ProductRepository) { } public build(): CartCreationService { return new CartCreationService( this._productRepo, new CartModificationService(), new CartRepository(this.appContext), new UrlBuilder(this.appContext), new RequestService(this.appContext), new UserSettingsRepository(this.appContext), new AppSettingsServiceFactory(this.appContext).build(), new DiscountServiceFactory(this.appContext).build(), new CartCreateUtils(), new FFLDealerRepository(this.appContext), ); } }