GET /customer/wallet now reads the EnakPoint & EnakCoin wallet (docs/prd-point-coin.md F6, PC-106): spendable point and coin balances, the rupiah value of one EnakPoint and of the balance, the nearest day each currency loses balance (grouped by Asia/Jakarta day), and recent ledger rows. The fields of the pre-wallet response stay, filled from the wallet, so app versions that read them keep working. Adds GET /customer/wallet/transactions with pagination and filters for currency, one or more types, and an inclusive date range. Each row shows where the value came from (additions) or went to (deductions) as in ยง8.1, and additions list their lots and earliest expiry. The counterparty id, the admin and the metadata are left out; the description already carries the masked name. A malformed query answers 400, a missing customer 404. /customer/points and /customer/tokens keep their shape and now read the wallet too, so customer_points_repository is no longer used for balances. Balances are what the customer can spend: lots that have expired but that the expiry job has not processed are not counted. The point value is read from organization_settings (loyalty.point.value, default 1) through a small repository that the typed settings reader in PC-109 will build on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
640 lines
36 KiB
Go
640 lines
36 KiB
Go
package app
|
|
|
|
import (
|
|
"apskel-pos-be/internal/client"
|
|
"apskel-pos-be/internal/transformer"
|
|
"context"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"apskel-pos-be/config"
|
|
"apskel-pos-be/internal/handler"
|
|
"apskel-pos-be/internal/middleware"
|
|
"apskel-pos-be/internal/processor"
|
|
"apskel-pos-be/internal/repository"
|
|
"apskel-pos-be/internal/router"
|
|
"apskel-pos-be/internal/service"
|
|
"apskel-pos-be/internal/validator"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type App struct {
|
|
server *http.Server
|
|
db *gorm.DB
|
|
redisClient *redis.Client
|
|
router *router.Router
|
|
shutdown chan os.Signal
|
|
omsetScheduler *service.OmsetMilestoneScheduler
|
|
}
|
|
|
|
func NewApp(db *gorm.DB, redisClient *redis.Client) *App {
|
|
return &App{
|
|
db: db,
|
|
redisClient: redisClient,
|
|
shutdown: make(chan os.Signal, 1),
|
|
}
|
|
}
|
|
|
|
func (a *App) Initialize(cfg *config.Config) error {
|
|
repos := a.initRepositories()
|
|
processors := a.initProcessors(cfg, repos)
|
|
|
|
// Initialize omset milestone scheduler
|
|
a.omsetScheduler = service.NewOmsetMilestoneScheduler(
|
|
repos.organizationRepo,
|
|
repos.outletRepo,
|
|
repos.userRepo,
|
|
processors.notificationProcessor,
|
|
)
|
|
|
|
services := a.initServices(processors, repos, cfg)
|
|
validators := a.initValidators()
|
|
middleware := a.initMiddleware(services, cfg)
|
|
healthHandler := handler.NewHealthHandler()
|
|
selfOrderHandler := handler.NewSelfOrderHandler(
|
|
services.orderService,
|
|
services.categoryService,
|
|
services.productService,
|
|
repos.tableRepo,
|
|
repos.outletRepo,
|
|
repos.userRepo,
|
|
repos.sessionRepo,
|
|
repos.orderRepo,
|
|
services.productOutletPriceService,
|
|
)
|
|
|
|
a.router = router.NewRouter(
|
|
cfg,
|
|
healthHandler,
|
|
services.authService,
|
|
middleware.authMiddleware,
|
|
services.userService,
|
|
validators.userValidator,
|
|
services.organizationService,
|
|
validators.organizationValidator,
|
|
services.outletService,
|
|
validators.outletValidator,
|
|
services.outletSettingService,
|
|
services.categoryService,
|
|
validators.categoryValidator,
|
|
services.productService,
|
|
validators.productValidator,
|
|
services.productVariantService,
|
|
validators.productVariantValidator,
|
|
services.inventoryService,
|
|
validators.inventoryValidator,
|
|
services.orderService,
|
|
validators.orderValidator,
|
|
services.fileService,
|
|
validators.fileValidator,
|
|
services.customerService,
|
|
validators.customerValidator,
|
|
services.paymentMethodService,
|
|
validators.paymentMethodValidator,
|
|
services.analyticsService,
|
|
services.reportService,
|
|
services.tableService,
|
|
validators.tableValidator,
|
|
services.unitService,
|
|
services.ingredientService,
|
|
services.productRecipeService,
|
|
services.vendorService,
|
|
validators.vendorValidator,
|
|
services.purchaseOrderService,
|
|
validators.purchaseOrderValidator,
|
|
services.purchaseCategoryService,
|
|
validators.purchaseCategoryValidator,
|
|
services.unitConverterService,
|
|
validators.unitConverterValidator,
|
|
services.chartOfAccountTypeService,
|
|
validators.chartOfAccountTypeValidator,
|
|
services.chartOfAccountService,
|
|
validators.chartOfAccountValidator,
|
|
services.accountService,
|
|
validators.accountValidator,
|
|
*services.orderIngredientTransactionService,
|
|
validators.orderIngredientTransactionValidator,
|
|
services.gamificationService,
|
|
validators.gamificationValidator,
|
|
services.rewardService,
|
|
validators.rewardValidator,
|
|
services.campaignService,
|
|
validators.campaignValidator,
|
|
services.customerAuthService,
|
|
validators.customerAuthValidator,
|
|
services.customerPointsService,
|
|
services.spinGameService,
|
|
middleware.customerAuthMiddleware,
|
|
services.userDeviceService,
|
|
validators.userDeviceValidator,
|
|
services.notificationService,
|
|
validators.notificationValidator,
|
|
services.productOutletPriceService,
|
|
validators.productOutletPriceValidator,
|
|
selfOrderHandler,
|
|
services.expenseService,
|
|
validators.expenseValidator,
|
|
services.cashAdvanceService,
|
|
validators.cashAdvanceValidator,
|
|
a.redisClient,
|
|
)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *App) Start(port string) error {
|
|
// Start the omset milestone scheduler (checks every 5 minutes for daily omset milestones)
|
|
if a.omsetScheduler != nil {
|
|
a.omsetScheduler.Start(5 * time.Minute)
|
|
}
|
|
|
|
engine := a.router.Init()
|
|
|
|
a.server = &http.Server{
|
|
Addr: ":" + port,
|
|
Handler: engine,
|
|
ReadTimeout: 15 * time.Second,
|
|
WriteTimeout: 15 * time.Second,
|
|
IdleTimeout: 60 * time.Second,
|
|
}
|
|
|
|
signal.Notify(a.shutdown, os.Interrupt, syscall.SIGTERM)
|
|
|
|
go func() {
|
|
log.Printf("Server starting on port %s", port)
|
|
if err := a.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Fatalf("Failed to start server: %v", err)
|
|
}
|
|
}()
|
|
|
|
<-a.shutdown
|
|
log.Println("Shutting down server...")
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
if err := a.server.Shutdown(ctx); err != nil {
|
|
log.Printf("Server forced to shutdown: %v", err)
|
|
return err
|
|
}
|
|
|
|
log.Println("Server exited gracefully")
|
|
return nil
|
|
}
|
|
|
|
func (a *App) Shutdown() {
|
|
if a.omsetScheduler != nil {
|
|
a.omsetScheduler.Stop()
|
|
}
|
|
close(a.shutdown)
|
|
}
|
|
|
|
type repositories struct {
|
|
userRepo *repository.UserRepositoryImpl
|
|
organizationRepo *repository.OrganizationRepositoryImpl
|
|
outletRepo *repository.OutletRepositoryImpl
|
|
outletSettingRepo *repository.OutletSettingRepositoryImpl
|
|
categoryRepo *repository.CategoryRepositoryImpl
|
|
productRepo *repository.ProductRepositoryImpl
|
|
productVariantRepo *repository.ProductVariantRepositoryImpl
|
|
inventoryRepo *repository.InventoryRepositoryImpl
|
|
inventoryMovementRepo *repository.InventoryMovementRepositoryImpl
|
|
orderRepo *repository.OrderRepositoryImpl
|
|
orderItemRepo *repository.OrderItemRepositoryImpl
|
|
paymentRepo *repository.PaymentRepositoryImpl
|
|
paymentOrderItemRepo *repository.PaymentOrderItemRepositoryImpl
|
|
paymentMethodRepo *repository.PaymentMethodRepositoryImpl
|
|
fileRepo *repository.FileRepositoryImpl
|
|
customerRepo *repository.CustomerRepository
|
|
analyticsRepo *repository.AnalyticsRepositoryImpl
|
|
tableRepo *repository.TableRepository
|
|
unitRepo *repository.UnitRepository
|
|
ingredientRepo *repository.IngredientRepository
|
|
ingredientCompositionRepo *repository.IngredientCompositionRepository
|
|
productRecipeRepo *repository.ProductRecipeRepository
|
|
vendorRepo *repository.VendorRepositoryImpl
|
|
purchaseOrderRepo *repository.PurchaseOrderRepositoryImpl
|
|
purchaseCategoryRepo *repository.PurchaseCategoryRepositoryImpl
|
|
unitConverterRepo *repository.IngredientUnitConverterRepositoryImpl
|
|
chartOfAccountTypeRepo *repository.ChartOfAccountTypeRepositoryImpl
|
|
chartOfAccountRepo *repository.ChartOfAccountRepositoryImpl
|
|
accountRepo *repository.AccountRepositoryImpl
|
|
orderIngredientTransactionRepo *repository.OrderIngredientTransactionRepositoryImpl
|
|
customerTokensRepo *repository.CustomerTokensRepository
|
|
tierRepo *repository.TierRepository
|
|
gameRepo *repository.GameRepository
|
|
gamePrizeRepo *repository.GamePrizeRepository
|
|
gamePlayRepo repository.GamePlayRepository
|
|
omsetTrackerRepo *repository.OmsetTrackerRepository
|
|
rewardRepo repository.RewardRepository
|
|
campaignRepo repository.CampaignRepository
|
|
campaignRuleRepo repository.CampaignRuleRepository
|
|
customerAuthRepo repository.CustomerAuthRepository
|
|
customerPointsRepo repository.CustomerPointsRepository
|
|
otpRepo repository.OtpRepository
|
|
sessionRepo repository.SessionRepository
|
|
txManager *repository.TxManager
|
|
userDeviceRepo *repository.UserDeviceRepositoryImpl
|
|
notificationRepo *repository.NotificationRepositoryImpl
|
|
notificationReceiverRepo *repository.NotificationReceiverRepositoryImpl
|
|
notificationDeliveryRepo *repository.NotificationDeliveryRepositoryImpl
|
|
productOutletPriceRepo *repository.ProductOutletPriceRepositoryImpl
|
|
expenseRepo *repository.ExpenseRepositoryImpl
|
|
cashAdvanceRepo *repository.CashAdvanceRepositoryImpl
|
|
walletRepo repository.WalletRepository
|
|
walletQueryRepo repository.WalletQueryRepository
|
|
organizationSettingRepo repository.OrganizationSettingRepository
|
|
}
|
|
|
|
func (a *App) initRepositories() *repositories {
|
|
return &repositories{
|
|
userRepo: repository.NewUserRepository(a.db),
|
|
organizationRepo: repository.NewOrganizationRepositoryImpl(a.db),
|
|
outletRepo: repository.NewOutletRepositoryImpl(a.db),
|
|
outletSettingRepo: repository.NewOutletSettingRepositoryImpl(a.db),
|
|
categoryRepo: repository.NewCategoryRepositoryImpl(a.db),
|
|
productRepo: repository.NewProductRepositoryImpl(a.db),
|
|
productVariantRepo: repository.NewProductVariantRepositoryImpl(a.db),
|
|
inventoryRepo: repository.NewInventoryRepositoryImpl(a.db),
|
|
inventoryMovementRepo: repository.NewInventoryMovementRepositoryImpl(a.db),
|
|
orderRepo: repository.NewOrderRepositoryImpl(a.db),
|
|
orderItemRepo: repository.NewOrderItemRepositoryImpl(a.db),
|
|
paymentRepo: repository.NewPaymentRepositoryImpl(a.db),
|
|
paymentOrderItemRepo: repository.NewPaymentOrderItemRepositoryImpl(a.db),
|
|
paymentMethodRepo: repository.NewPaymentMethodRepositoryImpl(a.db),
|
|
fileRepo: repository.NewFileRepositoryImpl(a.db),
|
|
customerRepo: repository.NewCustomerRepository(a.db),
|
|
analyticsRepo: repository.NewAnalyticsRepositoryImpl(a.db),
|
|
tableRepo: repository.NewTableRepository(a.db),
|
|
unitRepo: repository.NewUnitRepository(a.db),
|
|
ingredientRepo: repository.NewIngredientRepository(a.db),
|
|
ingredientCompositionRepo: repository.NewIngredientCompositionRepository(a.db),
|
|
productRecipeRepo: repository.NewProductRecipeRepository(a.db),
|
|
vendorRepo: repository.NewVendorRepositoryImpl(a.db),
|
|
purchaseOrderRepo: repository.NewPurchaseOrderRepositoryImpl(a.db),
|
|
purchaseCategoryRepo: repository.NewPurchaseCategoryRepositoryImpl(a.db),
|
|
unitConverterRepo: repository.NewIngredientUnitConverterRepositoryImpl(a.db).(*repository.IngredientUnitConverterRepositoryImpl),
|
|
chartOfAccountTypeRepo: repository.NewChartOfAccountTypeRepositoryImpl(a.db),
|
|
chartOfAccountRepo: repository.NewChartOfAccountRepositoryImpl(a.db),
|
|
accountRepo: repository.NewAccountRepositoryImpl(a.db),
|
|
orderIngredientTransactionRepo: repository.NewOrderIngredientTransactionRepositoryImpl(a.db).(*repository.OrderIngredientTransactionRepositoryImpl),
|
|
customerTokensRepo: repository.NewCustomerTokensRepository(a.db),
|
|
tierRepo: repository.NewTierRepository(a.db),
|
|
gameRepo: repository.NewGameRepository(a.db),
|
|
gamePrizeRepo: repository.NewGamePrizeRepository(a.db),
|
|
gamePlayRepo: repository.NewGamePlayRepository(a.db),
|
|
omsetTrackerRepo: repository.NewOmsetTrackerRepository(a.db),
|
|
rewardRepo: repository.NewRewardRepository(a.db),
|
|
campaignRepo: repository.NewCampaignRepository(a.db),
|
|
campaignRuleRepo: repository.NewCampaignRuleRepository(a.db),
|
|
customerAuthRepo: repository.NewCustomerAuthRepository(a.db),
|
|
customerPointsRepo: repository.NewCustomerPointsRepository(a.db),
|
|
otpRepo: repository.NewOtpRepository(a.db),
|
|
sessionRepo: repository.NewSessionRepository(a.redisClient),
|
|
txManager: repository.NewTxManager(a.db),
|
|
userDeviceRepo: repository.NewUserDeviceRepositoryImpl(a.db),
|
|
notificationRepo: repository.NewNotificationRepository(a.db),
|
|
notificationReceiverRepo: repository.NewNotificationReceiverRepository(a.db),
|
|
notificationDeliveryRepo: repository.NewNotificationDeliveryRepository(a.db),
|
|
productOutletPriceRepo: repository.NewProductOutletPriceRepositoryImpl(a.db),
|
|
expenseRepo: repository.NewExpenseRepositoryImpl(a.db),
|
|
cashAdvanceRepo: repository.NewCashAdvanceRepositoryImpl(a.db),
|
|
walletRepo: repository.NewWalletRepository(a.db),
|
|
walletQueryRepo: repository.NewWalletQueryRepository(a.db),
|
|
organizationSettingRepo: repository.NewOrganizationSettingRepository(a.db),
|
|
}
|
|
}
|
|
|
|
type processors struct {
|
|
userProcessor *processor.UserProcessorImpl
|
|
organizationProcessor processor.OrganizationProcessor
|
|
outletProcessor processor.OutletProcessor
|
|
outletSettingProcessor *processor.OutletSettingProcessorImpl
|
|
categoryProcessor processor.CategoryProcessor
|
|
productProcessor processor.ProductProcessor
|
|
productVariantProcessor processor.ProductVariantProcessor
|
|
inventoryProcessor processor.InventoryProcessor
|
|
orderProcessor processor.OrderProcessor
|
|
paymentMethodProcessor processor.PaymentMethodProcessor
|
|
fileProcessor processor.FileProcessor
|
|
customerProcessor *processor.CustomerProcessor
|
|
analyticsProcessor *processor.AnalyticsProcessorImpl
|
|
tableProcessor *processor.TableProcessor
|
|
unitProcessor *processor.UnitProcessorImpl
|
|
ingredientProcessor *processor.IngredientProcessorImpl
|
|
productRecipeProcessor *processor.ProductRecipeProcessorImpl
|
|
vendorProcessor *processor.VendorProcessorImpl
|
|
purchaseOrderProcessor *processor.PurchaseOrderProcessorImpl
|
|
purchaseCategoryProcessor *processor.PurchaseCategoryProcessorImpl
|
|
unitConverterProcessor *processor.IngredientUnitConverterProcessorImpl
|
|
chartOfAccountTypeProcessor *processor.ChartOfAccountTypeProcessorImpl
|
|
chartOfAccountProcessor *processor.ChartOfAccountProcessorImpl
|
|
accountProcessor *processor.AccountProcessorImpl
|
|
orderIngredientTransactionProcessor *processor.OrderIngredientTransactionProcessorImpl
|
|
customerTokensProcessor *processor.CustomerTokensProcessor
|
|
tierProcessor *processor.TierProcessor
|
|
gameProcessor *processor.GameProcessor
|
|
gamePrizeProcessor *processor.GamePrizeProcessor
|
|
gamePlayProcessor *processor.GamePlayProcessor
|
|
omsetTrackerProcessor *processor.OmsetTrackerProcessor
|
|
rewardProcessor processor.RewardProcessor
|
|
campaignProcessor processor.CampaignProcessor
|
|
campaignRuleProcessor processor.CampaignRuleProcessor
|
|
customerAuthProcessor processor.CustomerAuthProcessor
|
|
customerPointsProcessor *processor.CustomerPointsProcessor
|
|
otpProcessor processor.OtpProcessor
|
|
fileClient processor.FileClient
|
|
inventoryMovementService service.InventoryMovementService
|
|
userDeviceProcessor *processor.UserDeviceProcessorImpl
|
|
notificationProcessor *processor.NotificationProcessorImpl
|
|
productOutletPriceProcessor processor.ProductOutletPriceProcessor
|
|
expenseProcessor *processor.ExpenseProcessorImpl
|
|
cashAdvanceProcessor *processor.CashAdvanceProcessorImpl
|
|
walletProcessor *processor.WalletProcessor
|
|
}
|
|
|
|
func (a *App) initProcessors(cfg *config.Config, repos *repositories) *processors {
|
|
fileClient := client.NewFileClient(cfg.S3Config)
|
|
fonnteClient := client.NewFonnteClient(cfg.GetFonnte())
|
|
otpProcessor := processor.NewOtpProcessor(fonnteClient, repos.otpRepo)
|
|
inventoryMovementService := service.NewInventoryMovementService(repos.inventoryMovementRepo, repos.ingredientRepo)
|
|
|
|
return &processors{
|
|
userProcessor: processor.NewUserProcessor(repos.userRepo, repos.organizationRepo, repos.outletRepo),
|
|
organizationProcessor: processor.NewOrganizationProcessorImpl(repos.organizationRepo, repos.outletRepo, repos.userRepo),
|
|
outletProcessor: processor.NewOutletProcessorImpl(repos.outletRepo),
|
|
outletSettingProcessor: processor.NewOutletSettingProcessorImpl(repos.outletSettingRepo, repos.outletRepo),
|
|
categoryProcessor: processor.NewCategoryProcessorImpl(repos.categoryRepo),
|
|
productProcessor: processor.NewProductProcessorImpl(repos.productRepo, repos.categoryRepo, repos.productVariantRepo, repos.inventoryRepo, repos.outletRepo, repos.productOutletPriceRepo),
|
|
productVariantProcessor: processor.NewProductVariantProcessorImpl(repos.productVariantRepo, repos.productRepo),
|
|
inventoryProcessor: processor.NewInventoryProcessorImpl(repos.inventoryRepo, repos.productRepo, repos.outletRepo, repos.ingredientRepo, repos.inventoryMovementRepo),
|
|
orderProcessor: processor.NewOrderProcessorImpl(repos.orderRepo, repos.orderItemRepo, repos.paymentRepo, repos.paymentOrderItemRepo, repos.productRepo, repos.paymentMethodRepo, repos.inventoryRepo, repos.inventoryMovementRepo, repos.productVariantRepo, repos.outletRepo, repos.customerRepo, repos.txManager, repos.productRecipeRepo, repos.ingredientRepo, inventoryMovementService, repos.productOutletPriceRepo),
|
|
paymentMethodProcessor: processor.NewPaymentMethodProcessorImpl(repos.paymentMethodRepo),
|
|
fileProcessor: processor.NewFileProcessorImpl(repos.fileRepo, fileClient),
|
|
customerProcessor: processor.NewCustomerProcessor(repos.customerRepo),
|
|
analyticsProcessor: processor.NewAnalyticsProcessorImpl(repos.analyticsRepo, repos.expenseRepo),
|
|
tableProcessor: processor.NewTableProcessor(repos.tableRepo, repos.orderRepo),
|
|
unitProcessor: processor.NewUnitProcessor(repos.unitRepo),
|
|
ingredientProcessor: processor.NewIngredientProcessor(repos.ingredientRepo, repos.unitRepo, repos.ingredientCompositionRepo),
|
|
productRecipeProcessor: processor.NewProductRecipeProcessor(repos.productRecipeRepo, repos.productRepo, repos.ingredientRepo),
|
|
vendorProcessor: processor.NewVendorProcessorImpl(repos.vendorRepo),
|
|
purchaseOrderProcessor: processor.NewPurchaseOrderProcessorImpl(repos.purchaseOrderRepo, repos.vendorRepo, repos.ingredientRepo, repos.purchaseCategoryRepo, repos.categoryRepo, repos.cashAdvanceRepo, repos.unitRepo, repos.fileRepo, inventoryMovementService, repos.unitConverterRepo),
|
|
purchaseCategoryProcessor: processor.NewPurchaseCategoryProcessorImpl(repos.purchaseCategoryRepo),
|
|
unitConverterProcessor: processor.NewIngredientUnitConverterProcessorImpl(repos.unitConverterRepo, repos.ingredientRepo, repos.unitRepo),
|
|
chartOfAccountTypeProcessor: processor.NewChartOfAccountTypeProcessorImpl(repos.chartOfAccountTypeRepo),
|
|
chartOfAccountProcessor: processor.NewChartOfAccountProcessorImpl(repos.chartOfAccountRepo, repos.chartOfAccountTypeRepo),
|
|
accountProcessor: processor.NewAccountProcessorImpl(repos.accountRepo, repos.chartOfAccountRepo),
|
|
orderIngredientTransactionProcessor: processor.NewOrderIngredientTransactionProcessorImpl(repos.orderIngredientTransactionRepo, repos.productRecipeRepo, repos.ingredientRepo, repos.unitRepo).(*processor.OrderIngredientTransactionProcessorImpl),
|
|
customerTokensProcessor: processor.NewCustomerTokensProcessor(repos.customerTokensRepo),
|
|
tierProcessor: processor.NewTierProcessor(repos.tierRepo),
|
|
gameProcessor: processor.NewGameProcessor(repos.gameRepo),
|
|
gamePrizeProcessor: processor.NewGamePrizeProcessor(repos.gamePrizeRepo),
|
|
gamePlayProcessor: processor.NewGamePlayProcessor(repos.gamePlayRepo, repos.gameRepo, repos.gamePrizeRepo, repos.customerTokensRepo, repos.customerPointsRepo),
|
|
omsetTrackerProcessor: processor.NewOmsetTrackerProcessor(repos.omsetTrackerRepo),
|
|
rewardProcessor: processor.NewRewardProcessor(repos.rewardRepo),
|
|
campaignProcessor: processor.NewCampaignProcessor(repos.campaignRepo),
|
|
campaignRuleProcessor: processor.NewCampaignRuleProcessor(repos.campaignRuleRepo),
|
|
customerAuthProcessor: processor.NewCustomerAuthProcessor(repos.customerAuthRepo, otpProcessor, repos.otpRepo, cfg.GetCustomerJWTSecret(), cfg.GetCustomerJWTExpiresTTL()),
|
|
customerPointsProcessor: processor.NewCustomerPointsProcessor(processor.NewWalletQueryProcessor(repos.walletQueryRepo, repos.organizationSettingRepo), repos.gameRepo),
|
|
otpProcessor: otpProcessor,
|
|
fileClient: fileClient,
|
|
inventoryMovementService: inventoryMovementService,
|
|
userDeviceProcessor: processor.NewUserDeviceProcessorImpl(repos.userDeviceRepo),
|
|
notificationProcessor: buildNotificationProcessor(cfg, repos),
|
|
productOutletPriceProcessor: processor.NewProductOutletPriceProcessorImpl(repos.productOutletPriceRepo, repos.productRepo, repos.outletRepo),
|
|
expenseProcessor: processor.NewExpenseProcessorImpl(repos.expenseRepo, repos.purchaseCategoryRepo, repos.cashAdvanceRepo),
|
|
cashAdvanceProcessor: processor.NewCashAdvanceProcessorImpl(repos.cashAdvanceRepo, repos.categoryRepo),
|
|
walletProcessor: processor.NewWalletProcessor(repos.walletRepo),
|
|
}
|
|
}
|
|
|
|
type services struct {
|
|
userService *service.UserServiceImpl
|
|
authService service.AuthService
|
|
organizationService service.OrganizationService
|
|
outletService service.OutletService
|
|
outletSettingService service.OutletSettingService
|
|
categoryService service.CategoryService
|
|
productService service.ProductService
|
|
productVariantService service.ProductVariantService
|
|
inventoryService service.InventoryService
|
|
orderService service.OrderService
|
|
paymentMethodService service.PaymentMethodService
|
|
fileService service.FileService
|
|
customerService service.CustomerService
|
|
analyticsService *service.AnalyticsServiceImpl
|
|
reportService service.ReportService
|
|
tableService *service.TableServiceImpl
|
|
unitService *service.UnitServiceImpl
|
|
ingredientService *service.IngredientServiceImpl
|
|
productRecipeService *service.ProductRecipeServiceImpl
|
|
vendorService *service.VendorServiceImpl
|
|
purchaseOrderService *service.PurchaseOrderServiceImpl
|
|
purchaseCategoryService service.PurchaseCategoryService
|
|
unitConverterService *service.IngredientUnitConverterServiceImpl
|
|
chartOfAccountTypeService service.ChartOfAccountTypeService
|
|
chartOfAccountService service.ChartOfAccountService
|
|
accountService service.AccountService
|
|
orderIngredientTransactionService *service.OrderIngredientTransactionService
|
|
gamificationService service.GamificationService
|
|
rewardService service.RewardService
|
|
campaignService service.CampaignService
|
|
customerAuthService service.CustomerAuthService
|
|
customerPointsService service.CustomerPointsService
|
|
spinGameService service.SpinGameService
|
|
userDeviceService service.UserDeviceService
|
|
notificationService service.NotificationService
|
|
productOutletPriceService service.ProductOutletPriceService
|
|
expenseService *service.ExpenseServiceImpl
|
|
cashAdvanceService *service.CashAdvanceServiceImpl
|
|
}
|
|
|
|
func (a *App) initServices(processors *processors, repos *repositories, cfg *config.Config) *services {
|
|
authConfig := cfg.Auth()
|
|
authService := service.NewAuthService(processors.userProcessor, processors.userDeviceProcessor, authConfig)
|
|
organizationService := service.NewOrganizationService(processors.organizationProcessor)
|
|
outletService := service.NewOutletService(processors.outletProcessor)
|
|
outletSettingService := service.NewOutletSettingService(processors.outletSettingProcessor)
|
|
categoryService := service.NewCategoryService(processors.categoryProcessor)
|
|
productService := service.NewProductService(processors.productProcessor)
|
|
productVariantService := service.NewProductVariantService(processors.productVariantProcessor)
|
|
inventoryService := service.NewInventoryService(processors.inventoryProcessor)
|
|
orderService := service.NewOrderServiceImpl(processors.orderProcessor, repos.tableRepo, nil, processors.orderIngredientTransactionProcessor, *repos.productRecipeRepo, repos.txManager, repos.sessionRepo, processors.notificationProcessor, repos.userRepo) // Will be updated after orderIngredientTransactionService is created
|
|
paymentMethodService := service.NewPaymentMethodService(processors.paymentMethodProcessor)
|
|
fileService := service.NewFileServiceImpl(processors.fileProcessor)
|
|
var customerService service.CustomerService = service.NewCustomerService(processors.customerProcessor)
|
|
analyticsService := service.NewAnalyticsServiceImpl(processors.analyticsProcessor)
|
|
reportService := service.NewReportService(analyticsService, repos.organizationRepo, repos.outletRepo, processors.fileClient)
|
|
tableService := service.NewTableService(processors.tableProcessor, transformer.NewTableTransformer())
|
|
unitService := service.NewUnitService(processors.unitProcessor)
|
|
ingredientService := service.NewIngredientService(processors.ingredientProcessor)
|
|
productRecipeService := service.NewProductRecipeService(processors.productRecipeProcessor)
|
|
vendorService := service.NewVendorService(processors.vendorProcessor)
|
|
purchaseOrderService := service.NewPurchaseOrderService(processors.purchaseOrderProcessor)
|
|
purchaseCategoryService := service.NewPurchaseCategoryService(processors.purchaseCategoryProcessor)
|
|
unitConverterService := service.NewIngredientUnitConverterService(processors.unitConverterProcessor)
|
|
chartOfAccountTypeService := service.NewChartOfAccountTypeService(processors.chartOfAccountTypeProcessor)
|
|
chartOfAccountService := service.NewChartOfAccountService(processors.chartOfAccountProcessor)
|
|
accountService := service.NewAccountService(processors.accountProcessor)
|
|
orderIngredientTransactionService := service.NewOrderIngredientTransactionService(processors.orderIngredientTransactionProcessor, repos.txManager)
|
|
gamificationService := service.NewGamificationService(processors.customerPointsProcessor, processors.customerTokensProcessor, processors.tierProcessor, processors.gameProcessor, processors.gamePrizeProcessor, processors.gamePlayProcessor, processors.omsetTrackerProcessor)
|
|
rewardService := service.NewRewardService(processors.rewardProcessor)
|
|
campaignService := service.NewCampaignService(processors.campaignProcessor, processors.campaignRuleProcessor)
|
|
customerAuthService := service.NewCustomerAuthService(processors.customerAuthProcessor)
|
|
customerPointsService := service.NewCustomerPointsService(processors.customerPointsProcessor)
|
|
spinGameService := service.NewSpinGameService(processors.gamePlayProcessor, repos.txManager)
|
|
userDeviceService := service.NewUserDeviceService(processors.userDeviceProcessor)
|
|
notificationService := service.NewNotificationService(processors.notificationProcessor)
|
|
|
|
// Update order service with order ingredient transaction service
|
|
orderService = service.NewOrderServiceImpl(processors.orderProcessor, repos.tableRepo, orderIngredientTransactionService, processors.orderIngredientTransactionProcessor, *repos.productRecipeRepo, repos.txManager, repos.sessionRepo, processors.notificationProcessor, repos.userRepo)
|
|
|
|
return &services{
|
|
userService: service.NewUserService(processors.userProcessor),
|
|
authService: authService,
|
|
organizationService: organizationService,
|
|
outletService: outletService,
|
|
outletSettingService: outletSettingService,
|
|
categoryService: categoryService,
|
|
productService: productService,
|
|
productVariantService: productVariantService,
|
|
inventoryService: inventoryService,
|
|
orderService: orderService,
|
|
paymentMethodService: paymentMethodService,
|
|
fileService: fileService,
|
|
customerService: customerService,
|
|
analyticsService: analyticsService,
|
|
reportService: reportService,
|
|
tableService: tableService,
|
|
unitService: unitService,
|
|
ingredientService: ingredientService,
|
|
productRecipeService: productRecipeService,
|
|
vendorService: vendorService,
|
|
purchaseOrderService: purchaseOrderService,
|
|
purchaseCategoryService: purchaseCategoryService,
|
|
unitConverterService: unitConverterService,
|
|
chartOfAccountTypeService: chartOfAccountTypeService,
|
|
chartOfAccountService: chartOfAccountService,
|
|
accountService: accountService,
|
|
orderIngredientTransactionService: orderIngredientTransactionService,
|
|
gamificationService: gamificationService,
|
|
rewardService: rewardService,
|
|
campaignService: campaignService,
|
|
customerAuthService: customerAuthService,
|
|
customerPointsService: customerPointsService,
|
|
spinGameService: spinGameService,
|
|
userDeviceService: userDeviceService,
|
|
notificationService: notificationService,
|
|
productOutletPriceService: service.NewProductOutletPriceService(processors.productOutletPriceProcessor),
|
|
expenseService: service.NewExpenseService(processors.expenseProcessor),
|
|
cashAdvanceService: service.NewCashAdvanceService(processors.cashAdvanceProcessor),
|
|
}
|
|
}
|
|
|
|
type middlewares struct {
|
|
authMiddleware *middleware.AuthMiddleware
|
|
customerAuthMiddleware *middleware.CustomerAuthMiddleware
|
|
}
|
|
|
|
func (a *App) initMiddleware(services *services, cfg *config.Config) *middlewares {
|
|
return &middlewares{
|
|
authMiddleware: middleware.NewAuthMiddleware(services.authService),
|
|
customerAuthMiddleware: middleware.NewCustomerAuthMiddleware(cfg.GetCustomerJWTSecret()),
|
|
}
|
|
}
|
|
|
|
type validators struct {
|
|
userValidator *validator.UserValidatorImpl
|
|
organizationValidator validator.OrganizationValidator
|
|
outletValidator validator.OutletValidator
|
|
categoryValidator validator.CategoryValidator
|
|
productValidator validator.ProductValidator
|
|
productVariantValidator validator.ProductVariantValidator
|
|
inventoryValidator validator.InventoryValidator
|
|
orderValidator validator.OrderValidator
|
|
paymentMethodValidator validator.PaymentMethodValidator
|
|
fileValidator validator.FileValidator
|
|
customerValidator validator.CustomerValidator
|
|
tableValidator *validator.TableValidator
|
|
vendorValidator *validator.VendorValidatorImpl
|
|
purchaseOrderValidator *validator.PurchaseOrderValidatorImpl
|
|
purchaseCategoryValidator *validator.PurchaseCategoryValidatorImpl
|
|
unitConverterValidator *validator.IngredientUnitConverterValidatorImpl
|
|
chartOfAccountTypeValidator *validator.ChartOfAccountTypeValidatorImpl
|
|
chartOfAccountValidator *validator.ChartOfAccountValidatorImpl
|
|
accountValidator *validator.AccountValidatorImpl
|
|
orderIngredientTransactionValidator *validator.OrderIngredientTransactionValidatorImpl
|
|
gamificationValidator *validator.GamificationValidatorImpl
|
|
rewardValidator validator.RewardValidator
|
|
campaignValidator validator.CampaignValidator
|
|
customerAuthValidator validator.CustomerAuthValidator
|
|
userDeviceValidator *validator.UserDeviceValidatorImpl
|
|
notificationValidator *validator.NotificationValidatorImpl
|
|
productOutletPriceValidator *validator.ProductOutletPriceValidatorImpl
|
|
expenseValidator *validator.ExpenseValidatorImpl
|
|
cashAdvanceValidator *validator.CashAdvanceValidatorImpl
|
|
}
|
|
|
|
func (a *App) initValidators() *validators {
|
|
return &validators{
|
|
userValidator: validator.NewUserValidator(),
|
|
organizationValidator: validator.NewOrganizationValidator(),
|
|
outletValidator: validator.NewOutletValidator(),
|
|
categoryValidator: validator.NewCategoryValidator(),
|
|
productValidator: validator.NewProductValidator(),
|
|
productVariantValidator: validator.NewProductVariantValidator(),
|
|
inventoryValidator: validator.NewInventoryValidator(),
|
|
orderValidator: validator.NewOrderValidator(),
|
|
paymentMethodValidator: validator.NewPaymentMethodValidator(),
|
|
fileValidator: validator.NewFileValidatorImpl(),
|
|
customerValidator: validator.NewCustomerValidator(),
|
|
tableValidator: validator.NewTableValidator(),
|
|
vendorValidator: validator.NewVendorValidator(),
|
|
purchaseOrderValidator: validator.NewPurchaseOrderValidator(),
|
|
purchaseCategoryValidator: validator.NewPurchaseCategoryValidator(),
|
|
unitConverterValidator: validator.NewIngredientUnitConverterValidator().(*validator.IngredientUnitConverterValidatorImpl),
|
|
chartOfAccountTypeValidator: validator.NewChartOfAccountTypeValidator().(*validator.ChartOfAccountTypeValidatorImpl),
|
|
chartOfAccountValidator: validator.NewChartOfAccountValidator().(*validator.ChartOfAccountValidatorImpl),
|
|
accountValidator: validator.NewAccountValidator().(*validator.AccountValidatorImpl),
|
|
orderIngredientTransactionValidator: validator.NewOrderIngredientTransactionValidator().(*validator.OrderIngredientTransactionValidatorImpl),
|
|
gamificationValidator: validator.NewGamificationValidator(),
|
|
rewardValidator: validator.NewRewardValidator(),
|
|
campaignValidator: validator.NewCampaignValidator(),
|
|
customerAuthValidator: validator.NewCustomerAuthValidator(),
|
|
userDeviceValidator: validator.NewUserDeviceValidator(),
|
|
notificationValidator: validator.NewNotificationValidator(),
|
|
productOutletPriceValidator: validator.NewProductOutletPriceValidator(),
|
|
expenseValidator: validator.NewExpenseValidator(),
|
|
cashAdvanceValidator: validator.NewCashAdvanceValidator(),
|
|
}
|
|
}
|
|
|
|
// buildNotificationProcessor creates the notification processor with FCM integration.
|
|
// If FCM is not configured, it returns a processor with a nil FCM client (FCM dispatch will be skipped).
|
|
func buildNotificationProcessor(cfg *config.Config, repos *repositories) *processor.NotificationProcessorImpl {
|
|
var fcmClient client.FCMClient
|
|
if cfg.FCM.CredentialsFile != "" {
|
|
var err error
|
|
fcmClient, err = client.NewFCMClient(&cfg.FCM)
|
|
if err != nil {
|
|
// FCM init failure is non-fatal; notifications will still be persisted.
|
|
fcmClient = nil
|
|
}
|
|
}
|
|
|
|
return processor.NewNotificationProcessor(
|
|
repos.notificationRepo,
|
|
repos.notificationReceiverRepo,
|
|
repos.notificationDeliveryRepo,
|
|
repos.userDeviceRepo,
|
|
repos.userRepo,
|
|
fcmClient,
|
|
)
|
|
}
|