Compare commits
No commits in common. "87540fa1b7007d59a37ec173bb358986335875fe" and "55119b3e916caed14fd46b9cf67ef78fb0e95955" have entirely different histories.
87540fa1b7
...
55119b3e91
@ -52,7 +52,6 @@ type UpdatePurchaseOrderItemRequest struct {
|
|||||||
type PurchaseOrderResponse struct {
|
type PurchaseOrderResponse struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
OrganizationID uuid.UUID `json:"organization_id"`
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
OutletID *uuid.UUID `json:"outlet_id"`
|
|
||||||
VendorID *uuid.UUID `json:"vendor_id"`
|
VendorID *uuid.UUID `json:"vendor_id"`
|
||||||
PONumber string `json:"po_number"`
|
PONumber string `json:"po_number"`
|
||||||
TransactionDate time.Time `json:"transaction_date"`
|
TransactionDate time.Time `json:"transaction_date"`
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import (
|
|||||||
type PurchaseOrder struct {
|
type PurchaseOrder struct {
|
||||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null" json:"organization_id" validate:"required"`
|
OrganizationID uuid.UUID `gorm:"type:uuid;not null" json:"organization_id" validate:"required"`
|
||||||
OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id" validate:"omitempty"`
|
|
||||||
VendorID *uuid.UUID `gorm:"type:uuid" json:"vendor_id" validate:"omitempty"`
|
VendorID *uuid.UUID `gorm:"type:uuid" json:"vendor_id" validate:"omitempty"`
|
||||||
PONumber string `gorm:"not null;size:50" json:"po_number" validate:"required,min=1,max=50"`
|
PONumber string `gorm:"not null;size:50" json:"po_number" validate:"required,min=1,max=50"`
|
||||||
TransactionDate time.Time `gorm:"type:date;not null" json:"transaction_date" validate:"required"`
|
TransactionDate time.Time `gorm:"type:date;not null" json:"transaction_date" validate:"required"`
|
||||||
@ -24,7 +23,6 @@ type PurchaseOrder struct {
|
|||||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||||
|
|
||||||
Organization *Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
Organization *Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||||
Outlet *Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
|
|
||||||
Vendor *Vendor `gorm:"foreignKey:VendorID" json:"vendor,omitempty"`
|
Vendor *Vendor `gorm:"foreignKey:VendorID" json:"vendor,omitempty"`
|
||||||
Items []PurchaseOrderItem `gorm:"foreignKey:PurchaseOrderID" json:"items,omitempty"`
|
Items []PurchaseOrderItem `gorm:"foreignKey:PurchaseOrderID" json:"items,omitempty"`
|
||||||
Attachments []PurchaseOrderAttachment `gorm:"foreignKey:PurchaseOrderID" json:"attachments,omitempty"`
|
Attachments []PurchaseOrderAttachment `gorm:"foreignKey:PurchaseOrderID" json:"attachments,omitempty"`
|
||||||
|
|||||||
@ -13,7 +13,6 @@ func PurchaseOrderEntityToModel(entity *entities.PurchaseOrder) *models.Purchase
|
|||||||
return &models.PurchaseOrder{
|
return &models.PurchaseOrder{
|
||||||
ID: entity.ID,
|
ID: entity.ID,
|
||||||
OrganizationID: entity.OrganizationID,
|
OrganizationID: entity.OrganizationID,
|
||||||
OutletID: entity.OutletID,
|
|
||||||
VendorID: entity.VendorID,
|
VendorID: entity.VendorID,
|
||||||
PONumber: entity.PONumber,
|
PONumber: entity.PONumber,
|
||||||
TransactionDate: entity.TransactionDate,
|
TransactionDate: entity.TransactionDate,
|
||||||
@ -35,7 +34,6 @@ func PurchaseOrderModelToEntity(model *models.PurchaseOrder) *entities.PurchaseO
|
|||||||
return &entities.PurchaseOrder{
|
return &entities.PurchaseOrder{
|
||||||
ID: model.ID,
|
ID: model.ID,
|
||||||
OrganizationID: model.OrganizationID,
|
OrganizationID: model.OrganizationID,
|
||||||
OutletID: model.OutletID,
|
|
||||||
VendorID: model.VendorID,
|
VendorID: model.VendorID,
|
||||||
PONumber: model.PONumber,
|
PONumber: model.PONumber,
|
||||||
TransactionDate: model.TransactionDate,
|
TransactionDate: model.TransactionDate,
|
||||||
@ -57,7 +55,6 @@ func PurchaseOrderEntityToResponse(entity *entities.PurchaseOrder) *models.Purch
|
|||||||
response := &models.PurchaseOrderResponse{
|
response := &models.PurchaseOrderResponse{
|
||||||
ID: entity.ID,
|
ID: entity.ID,
|
||||||
OrganizationID: entity.OrganizationID,
|
OrganizationID: entity.OrganizationID,
|
||||||
OutletID: entity.OutletID,
|
|
||||||
VendorID: entity.VendorID,
|
VendorID: entity.VendorID,
|
||||||
PONumber: entity.PONumber,
|
PONumber: entity.PONumber,
|
||||||
TransactionDate: entity.TransactionDate,
|
TransactionDate: entity.TransactionDate,
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import (
|
|||||||
type PurchaseOrder struct {
|
type PurchaseOrder struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
OrganizationID uuid.UUID `json:"organization_id"`
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
OutletID *uuid.UUID `json:"outlet_id"`
|
|
||||||
VendorID *uuid.UUID `json:"vendor_id"`
|
VendorID *uuid.UUID `json:"vendor_id"`
|
||||||
PONumber string `json:"po_number"`
|
PONumber string `json:"po_number"`
|
||||||
TransactionDate time.Time `json:"transaction_date"`
|
TransactionDate time.Time `json:"transaction_date"`
|
||||||
@ -45,7 +44,6 @@ type PurchaseOrderAttachment struct {
|
|||||||
type PurchaseOrderResponse struct {
|
type PurchaseOrderResponse struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
OrganizationID uuid.UUID `json:"organization_id"`
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
OutletID *uuid.UUID `json:"outlet_id"`
|
|
||||||
VendorID *uuid.UUID `json:"vendor_id"`
|
VendorID *uuid.UUID `json:"vendor_id"`
|
||||||
PONumber string `json:"po_number"`
|
PONumber string `json:"po_number"`
|
||||||
TransactionDate time.Time `json:"transaction_date"`
|
TransactionDate time.Time `json:"transaction_date"`
|
||||||
@ -87,7 +85,6 @@ type PurchaseOrderAttachmentResponse struct {
|
|||||||
|
|
||||||
type CreatePurchaseOrderRequest struct {
|
type CreatePurchaseOrderRequest struct {
|
||||||
VendorID *uuid.UUID `json:"vendor_id,omitempty"`
|
VendorID *uuid.UUID `json:"vendor_id,omitempty"`
|
||||||
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
|
||||||
PONumber string `json:"po_number"`
|
PONumber string `json:"po_number"`
|
||||||
TransactionDate time.Time `json:"transaction_date"`
|
TransactionDate time.Time `json:"transaction_date"`
|
||||||
DueDate *time.Time `json:"due_date,omitempty"`
|
DueDate *time.Time `json:"due_date,omitempty"`
|
||||||
|
|||||||
@ -11,8 +11,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PurchaseOrderProcessor interface {
|
type PurchaseOrderProcessor interface {
|
||||||
CreatePurchaseOrder(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, req *models.CreatePurchaseOrderRequest) (*models.PurchaseOrderResponse, error)
|
CreatePurchaseOrder(ctx context.Context, organizationID uuid.UUID, req *models.CreatePurchaseOrderRequest) (*models.PurchaseOrderResponse, error)
|
||||||
UpdatePurchaseOrder(ctx context.Context, id, organizationID uuid.UUID, outletID *uuid.UUID, req *models.UpdatePurchaseOrderRequest) (*models.PurchaseOrderResponse, error)
|
UpdatePurchaseOrder(ctx context.Context, id, organizationID uuid.UUID, req *models.UpdatePurchaseOrderRequest) (*models.PurchaseOrderResponse, error)
|
||||||
DeletePurchaseOrder(ctx context.Context, id, organizationID uuid.UUID) error
|
DeletePurchaseOrder(ctx context.Context, id, organizationID uuid.UUID) error
|
||||||
GetPurchaseOrderByID(ctx context.Context, id, organizationID uuid.UUID) (*models.PurchaseOrderResponse, error)
|
GetPurchaseOrderByID(ctx context.Context, id, organizationID uuid.UUID) (*models.PurchaseOrderResponse, error)
|
||||||
ListPurchaseOrders(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, page, limit int) ([]*models.PurchaseOrderResponse, int, error)
|
ListPurchaseOrders(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, page, limit int) ([]*models.PurchaseOrderResponse, int, error)
|
||||||
@ -54,7 +54,7 @@ func NewPurchaseOrderProcessorImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PurchaseOrderProcessorImpl) CreatePurchaseOrder(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, req *models.CreatePurchaseOrderRequest) (*models.PurchaseOrderResponse, error) {
|
func (p *PurchaseOrderProcessorImpl) CreatePurchaseOrder(ctx context.Context, organizationID uuid.UUID, req *models.CreatePurchaseOrderRequest) (*models.PurchaseOrderResponse, error) {
|
||||||
// Check if vendor exists and belongs to organization when provided.
|
// Check if vendor exists and belongs to organization when provided.
|
||||||
if req.VendorID != nil {
|
if req.VendorID != nil {
|
||||||
_, err := p.vendorRepo.GetByIDAndOrganizationID(ctx, *req.VendorID, organizationID)
|
_, err := p.vendorRepo.GetByIDAndOrganizationID(ctx, *req.VendorID, organizationID)
|
||||||
@ -115,7 +115,6 @@ func (p *PurchaseOrderProcessorImpl) CreatePurchaseOrder(ctx context.Context, or
|
|||||||
// Create purchase order entity
|
// Create purchase order entity
|
||||||
poEntity := &entities.PurchaseOrder{
|
poEntity := &entities.PurchaseOrder{
|
||||||
OrganizationID: organizationID,
|
OrganizationID: organizationID,
|
||||||
OutletID: outletID,
|
|
||||||
VendorID: req.VendorID,
|
VendorID: req.VendorID,
|
||||||
PONumber: req.PONumber,
|
PONumber: req.PONumber,
|
||||||
TransactionDate: req.TransactionDate,
|
TransactionDate: req.TransactionDate,
|
||||||
@ -176,15 +175,12 @@ func (p *PurchaseOrderProcessorImpl) CreatePurchaseOrder(ctx context.Context, or
|
|||||||
return mappers.PurchaseOrderEntityToResponse(createdPO), nil
|
return mappers.PurchaseOrderEntityToResponse(createdPO), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrder(ctx context.Context, id, organizationID uuid.UUID, outletID *uuid.UUID, req *models.UpdatePurchaseOrderRequest) (*models.PurchaseOrderResponse, error) {
|
func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrder(ctx context.Context, id, organizationID uuid.UUID, req *models.UpdatePurchaseOrderRequest) (*models.PurchaseOrderResponse, error) {
|
||||||
// Get existing purchase order
|
// Get existing purchase order
|
||||||
poEntity, err := p.purchaseOrderRepo.GetByIDAndOrganizationID(ctx, id, organizationID)
|
poEntity, err := p.purchaseOrderRepo.GetByIDAndOrganizationID(ctx, id, organizationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("purchase order not found: %w", err)
|
return nil, fmt.Errorf("purchase order not found: %w", err)
|
||||||
}
|
}
|
||||||
if poEntity.OutletID == nil && outletID != nil {
|
|
||||||
poEntity.OutletID = outletID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if vendor exists and belongs to organization (if vendor is being updated)
|
// Check if vendor exists and belongs to organization (if vendor is being updated)
|
||||||
if req.VendorID != nil {
|
if req.VendorID != nil {
|
||||||
@ -482,12 +478,7 @@ func (p *PurchaseOrderProcessorImpl) UpdatePurchaseOrderStatus(ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the purchase order status
|
// Update the purchase order status
|
||||||
statusOutletID := po.OutletID
|
err = p.purchaseOrderRepo.UpdateStatus(ctx, id, status)
|
||||||
if statusOutletID == nil && outletID != uuid.Nil {
|
|
||||||
statusOutletID = &outletID
|
|
||||||
}
|
|
||||||
|
|
||||||
err = p.purchaseOrderRepo.UpdateStatusAndOutlet(ctx, id, status, statusOutletID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to update purchase order status: %w", err)
|
return nil, fmt.Errorf("failed to update purchase order status: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,6 @@ type PurchaseOrderRepository interface {
|
|||||||
GetByStatus(ctx context.Context, organizationID uuid.UUID, status string) ([]*entities.PurchaseOrder, error)
|
GetByStatus(ctx context.Context, organizationID uuid.UUID, status string) ([]*entities.PurchaseOrder, error)
|
||||||
GetOverdue(ctx context.Context, organizationID uuid.UUID) ([]*entities.PurchaseOrder, error)
|
GetOverdue(ctx context.Context, organizationID uuid.UUID) ([]*entities.PurchaseOrder, error)
|
||||||
UpdateStatus(ctx context.Context, id uuid.UUID, status string) error
|
UpdateStatus(ctx context.Context, id uuid.UUID, status string) error
|
||||||
UpdateStatusAndOutlet(ctx context.Context, id uuid.UUID, status string, outletID *uuid.UUID) error
|
|
||||||
UpdateTotalAmount(ctx context.Context, id uuid.UUID, totalAmount float64) error
|
UpdateTotalAmount(ctx context.Context, id uuid.UUID, totalAmount float64) error
|
||||||
CreateItem(ctx context.Context, item *entities.PurchaseOrderItem) error
|
CreateItem(ctx context.Context, item *entities.PurchaseOrderItem) error
|
||||||
UpdateItem(ctx context.Context, item *entities.PurchaseOrderItem) error
|
UpdateItem(ctx context.Context, item *entities.PurchaseOrderItem) error
|
||||||
|
|||||||
@ -39,10 +39,6 @@ func (r *AnalyticsRepositoryImpl) resolveOutletID(query *gorm.DB, outletID *uuid
|
|||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
func purchaseOrderItemTotalAmountSQL() string {
|
|
||||||
return "CASE WHEN pc.type = '" + string(entities.PurchaseCategoryTypeRawMaterial) + "' THEN COALESCE(poi.quantity, 0) * poi.amount ELSE poi.amount END"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *AnalyticsRepositoryImpl) GetPaymentMethodAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) ([]*entities.PaymentMethodAnalytics, error) {
|
func (r *AnalyticsRepositoryImpl) GetPaymentMethodAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) ([]*entities.PaymentMethodAnalytics, error) {
|
||||||
var results []*entities.PaymentMethodAnalytics
|
var results []*entities.PaymentMethodAnalytics
|
||||||
|
|
||||||
@ -157,19 +153,18 @@ func (r *AnalyticsRepositoryImpl) getPurchaseOrderPurchasingAnalytics(ctx contex
|
|||||||
summaryQuery := r.db.WithContext(ctx).
|
summaryQuery := r.db.WithContext(ctx).
|
||||||
Table("purchase_orders po").
|
Table("purchase_orders po").
|
||||||
Select(`
|
Select(`
|
||||||
COALESCE(SUM(`+purchaseOrderItemTotalAmountSQL()+`), 0) as total_purchases,
|
COALESCE(SUM(poi.amount), 0) as total_purchases,
|
||||||
COUNT(DISTINCT po.id) as total_purchase_orders,
|
COUNT(DISTINCT po.id) as total_purchase_orders,
|
||||||
COALESCE(SUM(poi.quantity), 0) as total_quantity,
|
COALESCE(SUM(poi.quantity), 0) as total_quantity,
|
||||||
CASE
|
CASE
|
||||||
WHEN COUNT(DISTINCT po.id) > 0
|
WHEN COUNT(DISTINCT po.id) > 0
|
||||||
THEN COALESCE(SUM(`+purchaseOrderItemTotalAmountSQL()+`), 0) / COUNT(DISTINCT po.id)
|
THEN COALESCE(SUM(poi.amount), 0) / COUNT(DISTINCT po.id)
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END as average_purchase_order_value,
|
END as average_purchase_order_value,
|
||||||
COUNT(DISTINCT i.id) as total_ingredients,
|
COUNT(DISTINCT i.id) as total_ingredients,
|
||||||
COUNT(DISTINCT COALESCE(po.vendor_id::text, 'no-vendor')) as total_vendors
|
COUNT(DISTINCT COALESCE(po.vendor_id::text, 'no-vendor')) as total_vendors
|
||||||
`).
|
`).
|
||||||
Joins("LEFT JOIN purchase_order_items poi ON poi.purchase_order_id = po.id").
|
Joins("LEFT JOIN purchase_order_items poi ON poi.purchase_order_id = po.id").
|
||||||
Joins("LEFT JOIN purchase_categories pc ON poi.purchase_category_id = pc.id").
|
|
||||||
Joins("LEFT JOIN ingredients i ON poi.ingredient_id = i.id").
|
Joins("LEFT JOIN ingredients i ON poi.ingredient_id = i.id").
|
||||||
Joins("LEFT JOIN units u ON poi.unit_id = u.id").
|
Joins("LEFT JOIN units u ON poi.unit_id = u.id").
|
||||||
Where("po.organization_id = ?", organizationID).
|
Where("po.organization_id = ?", organizationID).
|
||||||
@ -198,14 +193,13 @@ func (r *AnalyticsRepositoryImpl) getPurchaseOrderPurchasingAnalytics(ctx contex
|
|||||||
Table("purchase_orders po").
|
Table("purchase_orders po").
|
||||||
Select(`
|
Select(`
|
||||||
`+dateFormat+` as date,
|
`+dateFormat+` as date,
|
||||||
COALESCE(SUM(`+purchaseOrderItemTotalAmountSQL()+`), 0) as purchases,
|
COALESCE(SUM(poi.amount), 0) as purchases,
|
||||||
COUNT(DISTINCT po.id) as purchase_orders,
|
COUNT(DISTINCT po.id) as purchase_orders,
|
||||||
COALESCE(SUM(poi.quantity), 0) as quantity,
|
COALESCE(SUM(poi.quantity), 0) as quantity,
|
||||||
COUNT(DISTINCT i.id) as ingredients,
|
COUNT(DISTINCT i.id) as ingredients,
|
||||||
COUNT(DISTINCT COALESCE(po.vendor_id::text, 'no-vendor')) as vendors
|
COUNT(DISTINCT COALESCE(po.vendor_id::text, 'no-vendor')) as vendors
|
||||||
`).
|
`).
|
||||||
Joins("LEFT JOIN purchase_order_items poi ON poi.purchase_order_id = po.id").
|
Joins("LEFT JOIN purchase_order_items poi ON poi.purchase_order_id = po.id").
|
||||||
Joins("LEFT JOIN purchase_categories pc ON poi.purchase_category_id = pc.id").
|
|
||||||
Joins("LEFT JOIN ingredients i ON poi.ingredient_id = i.id").
|
Joins("LEFT JOIN ingredients i ON poi.ingredient_id = i.id").
|
||||||
Joins("LEFT JOIN units u ON poi.unit_id = u.id").
|
Joins("LEFT JOIN units u ON poi.unit_id = u.id").
|
||||||
Where("po.organization_id = ?", organizationID).
|
Where("po.organization_id = ?", organizationID).
|
||||||
@ -226,16 +220,15 @@ func (r *AnalyticsRepositoryImpl) getPurchaseOrderPurchasingAnalytics(ctx contex
|
|||||||
i.id as ingredient_id,
|
i.id as ingredient_id,
|
||||||
i.name as ingredient_name,
|
i.name as ingredient_name,
|
||||||
COALESCE(SUM(poi.quantity), 0) as quantity,
|
COALESCE(SUM(poi.quantity), 0) as quantity,
|
||||||
COALESCE(SUM(`+purchaseOrderItemTotalAmountSQL()+`), 0) as total_cost,
|
COALESCE(SUM(poi.amount), 0) as total_cost,
|
||||||
CASE
|
CASE
|
||||||
WHEN SUM(poi.quantity) > 0
|
WHEN SUM(poi.quantity) > 0
|
||||||
THEN COALESCE(SUM(`+purchaseOrderItemTotalAmountSQL()+`), 0) / SUM(poi.quantity)
|
THEN COALESCE(SUM(poi.amount), 0) / SUM(poi.quantity)
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END as average_unit_cost,
|
END as average_unit_cost,
|
||||||
COUNT(DISTINCT po.id) as purchase_order_count
|
COUNT(DISTINCT po.id) as purchase_order_count
|
||||||
`).
|
`).
|
||||||
Joins("JOIN purchase_orders po ON poi.purchase_order_id = po.id").
|
Joins("JOIN purchase_orders po ON poi.purchase_order_id = po.id").
|
||||||
Joins("JOIN purchase_categories pc ON poi.purchase_category_id = pc.id").
|
|
||||||
Joins("JOIN ingredients i ON poi.ingredient_id = i.id").
|
Joins("JOIN ingredients i ON poi.ingredient_id = i.id").
|
||||||
Joins("LEFT JOIN units u ON poi.unit_id = u.id").
|
Joins("LEFT JOIN units u ON poi.unit_id = u.id").
|
||||||
Where("po.organization_id = ?", organizationID).
|
Where("po.organization_id = ?", organizationID).
|
||||||
@ -255,14 +248,13 @@ func (r *AnalyticsRepositoryImpl) getPurchaseOrderPurchasingAnalytics(ctx contex
|
|||||||
Select(`
|
Select(`
|
||||||
v.id as vendor_id,
|
v.id as vendor_id,
|
||||||
COALESCE(v.name, 'No Vendor') as vendor_name,
|
COALESCE(v.name, 'No Vendor') as vendor_name,
|
||||||
COALESCE(SUM(`+purchaseOrderItemTotalAmountSQL()+`), 0) as total_cost,
|
COALESCE(SUM(poi.amount), 0) as total_cost,
|
||||||
COUNT(DISTINCT po.id) as purchase_order_count,
|
COUNT(DISTINCT po.id) as purchase_order_count,
|
||||||
COUNT(DISTINCT i.id) as ingredient_count,
|
COUNT(DISTINCT i.id) as ingredient_count,
|
||||||
COALESCE(SUM(poi.quantity), 0) as quantity
|
COALESCE(SUM(poi.quantity), 0) as quantity
|
||||||
`).
|
`).
|
||||||
Joins("LEFT JOIN vendors v ON po.vendor_id = v.id").
|
Joins("LEFT JOIN vendors v ON po.vendor_id = v.id").
|
||||||
Joins("LEFT JOIN purchase_order_items poi ON poi.purchase_order_id = po.id").
|
Joins("LEFT JOIN purchase_order_items poi ON poi.purchase_order_id = po.id").
|
||||||
Joins("LEFT JOIN purchase_categories pc ON poi.purchase_category_id = pc.id").
|
|
||||||
Joins("LEFT JOIN ingredients i ON poi.ingredient_id = i.id").
|
Joins("LEFT JOIN ingredients i ON poi.ingredient_id = i.id").
|
||||||
Joins("LEFT JOIN units u ON poi.unit_id = u.id").
|
Joins("LEFT JOIN units u ON poi.unit_id = u.id").
|
||||||
Where("po.organization_id = ?", organizationID).
|
Where("po.organization_id = ?", organizationID).
|
||||||
@ -289,7 +281,7 @@ func (r *AnalyticsRepositoryImpl) applyPurchaseOrderItemOutletFilter(query *gorm
|
|||||||
if outletID == nil {
|
if outletID == nil {
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
return query.Where("po.outlet_id = ?", *outletID)
|
return query.Where("(i.outlet_id = ? OR u.outlet_id = ?)", *outletID, *outletID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *AnalyticsRepositoryImpl) GetProductAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, limit int) ([]*entities.ProductAnalytics, error) {
|
func (r *AnalyticsRepositoryImpl) GetProductAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, limit int) ([]*entities.ProductAnalytics, error) {
|
||||||
@ -725,7 +717,7 @@ func (r *AnalyticsRepositoryImpl) GetExclusiveSummaryAnalytics(ctx context.Conte
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
operationalExpenseBreakdown, err := r.getExclusiveSummaryOperationalExpenseBreakdown(ctx, organizationID, outletID, dateFrom, dateTo)
|
operationalExpenseBreakdown, err := r.getExclusiveSummaryOperationalExpenseBreakdown(ctx, organizationID, dateFrom, dateTo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -758,7 +750,7 @@ func (r *AnalyticsRepositoryImpl) getExclusiveSummaryHPPBreakdown(ctx context.Co
|
|||||||
Select(`
|
Select(`
|
||||||
pc.code as category_code,
|
pc.code as category_code,
|
||||||
pc.name as category_name,
|
pc.name as category_name,
|
||||||
COALESCE(SUM(`+purchaseOrderItemTotalAmountSQL()+`), 0) as amount
|
COALESCE(SUM(poi.amount), 0) as amount
|
||||||
`).
|
`).
|
||||||
Joins("JOIN purchase_orders po ON poi.purchase_order_id = po.id").
|
Joins("JOIN purchase_orders po ON poi.purchase_order_id = po.id").
|
||||||
Joins("JOIN purchase_categories pc ON poi.purchase_category_id = pc.id").
|
Joins("JOIN purchase_categories pc ON poi.purchase_category_id = pc.id").
|
||||||
@ -778,25 +770,22 @@ func (r *AnalyticsRepositoryImpl) getExclusiveSummaryHPPBreakdown(ctx context.Co
|
|||||||
return results, err
|
return results, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *AnalyticsRepositoryImpl) getExclusiveSummaryOperationalExpenseBreakdown(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) ([]entities.ExclusiveSummaryCategoryTotal, error) {
|
func (r *AnalyticsRepositoryImpl) getExclusiveSummaryOperationalExpenseBreakdown(ctx context.Context, organizationID uuid.UUID, dateFrom, dateTo time.Time) ([]entities.ExclusiveSummaryCategoryTotal, error) {
|
||||||
var results []entities.ExclusiveSummaryCategoryTotal
|
var results []entities.ExclusiveSummaryCategoryTotal
|
||||||
|
|
||||||
query := r.db.WithContext(ctx).
|
err := r.db.WithContext(ctx).
|
||||||
Table("purchase_order_items poi").
|
Table("purchase_order_items poi").
|
||||||
Select(`
|
Select(`
|
||||||
pc.code as category_code,
|
pc.code as category_code,
|
||||||
pc.name as category_name,
|
pc.name as category_name,
|
||||||
COALESCE(SUM(`+purchaseOrderItemTotalAmountSQL()+`), 0) as amount
|
COALESCE(SUM(poi.amount), 0) as amount
|
||||||
`).
|
`).
|
||||||
Joins("JOIN purchase_orders po ON poi.purchase_order_id = po.id").
|
Joins("JOIN purchase_orders po ON poi.purchase_order_id = po.id").
|
||||||
Joins("JOIN purchase_categories pc ON poi.purchase_category_id = pc.id").
|
Joins("JOIN purchase_categories pc ON poi.purchase_category_id = pc.id").
|
||||||
Where("po.organization_id = ?", organizationID).
|
Where("po.organization_id = ?", organizationID).
|
||||||
Where("pc.type = ?", entities.PurchaseCategoryTypeExpense).
|
Where("pc.type = ?", entities.PurchaseCategoryTypeExpense).
|
||||||
Where("po.status = ?", "received").
|
Where("po.status = ?", "received").
|
||||||
Where("po.transaction_date >= ? AND po.transaction_date <= ?", dateFrom, dateTo)
|
Where("po.transaction_date >= ? AND po.transaction_date <= ?", dateFrom, dateTo).
|
||||||
query = r.applyPurchaseOrderItemOutletFilter(query, outletID)
|
|
||||||
|
|
||||||
err := query.
|
|
||||||
Group("pc.id, pc.code, pc.name, pc.sort_order").
|
Group("pc.id, pc.code, pc.name, pc.sort_order").
|
||||||
Order("pc.sort_order ASC, pc.name ASC").
|
Order("pc.sort_order ASC, pc.name ASC").
|
||||||
Scan(&results).Error
|
Scan(&results).Error
|
||||||
@ -841,8 +830,8 @@ func (r *AnalyticsRepositoryImpl) exclusiveSummaryPurchaseOrderItemQuery(organiz
|
|||||||
}
|
}
|
||||||
|
|
||||||
if outletID != nil {
|
if outletID != nil {
|
||||||
outletFilter = "AND po.outlet_id = ?"
|
outletFilter = "AND (pc.type = ? OR i.outlet_id = ? OR u.outlet_id = ?)"
|
||||||
args = append(args, *outletID)
|
args = append(args, entities.PurchaseCategoryTypeExpense, *outletID, *outletID)
|
||||||
}
|
}
|
||||||
|
|
||||||
query := `
|
query := `
|
||||||
@ -851,7 +840,7 @@ func (r *AnalyticsRepositoryImpl) exclusiveSummaryPurchaseOrderItemQuery(organiz
|
|||||||
pc.code as category_code,
|
pc.code as category_code,
|
||||||
pc.name as category_name,
|
pc.name as category_name,
|
||||||
COALESCE(NULLIF(poi.description, ''), i.name, pc.name) as description,
|
COALESCE(NULLIF(poi.description, ''), i.name, pc.name) as description,
|
||||||
` + purchaseOrderItemTotalAmountSQL() + ` as amount,
|
poi.amount as amount,
|
||||||
'purchase_order' as source
|
'purchase_order' as source
|
||||||
FROM purchase_order_items poi
|
FROM purchase_order_items poi
|
||||||
JOIN purchase_orders po ON poi.purchase_order_id = po.id
|
JOIN purchase_orders po ON poi.purchase_order_id = po.id
|
||||||
|
|||||||
@ -196,18 +196,6 @@ func (r *PurchaseOrderRepositoryImpl) UpdateStatus(ctx context.Context, id uuid.
|
|||||||
Update("status", status).Error
|
Update("status", status).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PurchaseOrderRepositoryImpl) UpdateStatusAndOutlet(ctx context.Context, id uuid.UUID, status string, outletID *uuid.UUID) error {
|
|
||||||
updates := map[string]interface{}{"status": status}
|
|
||||||
if outletID != nil {
|
|
||||||
updates["outlet_id"] = *outletID
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.db.WithContext(ctx).
|
|
||||||
Model(&entities.PurchaseOrder{}).
|
|
||||||
Where("id = ?", id).
|
|
||||||
Updates(updates).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *PurchaseOrderRepositoryImpl) UpdateTotalAmount(ctx context.Context, id uuid.UUID, totalAmount float64) error {
|
func (r *PurchaseOrderRepositoryImpl) UpdateTotalAmount(ctx context.Context, id uuid.UUID, totalAmount float64) error {
|
||||||
return r.db.WithContext(ctx).
|
return r.db.WithContext(ctx).
|
||||||
Model(&entities.PurchaseOrder{}).
|
Model(&entities.PurchaseOrder{}).
|
||||||
|
|||||||
@ -40,12 +40,7 @@ func (s *PurchaseOrderServiceImpl) CreatePurchaseOrder(ctx context.Context, apct
|
|||||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||||
}
|
}
|
||||||
|
|
||||||
var outletID *uuid.UUID
|
poResponse, err := s.purchaseOrderProcessor.CreatePurchaseOrder(ctx, apctx.OrganizationID, modelReq)
|
||||||
if apctx.OutletID != uuid.Nil {
|
|
||||||
outletID = &apctx.OutletID
|
|
||||||
}
|
|
||||||
|
|
||||||
poResponse, err := s.purchaseOrderProcessor.CreatePurchaseOrder(ctx, apctx.OrganizationID, outletID, modelReq)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
|
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
|
||||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||||
@ -62,12 +57,7 @@ func (s *PurchaseOrderServiceImpl) UpdatePurchaseOrder(ctx context.Context, apct
|
|||||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||||
}
|
}
|
||||||
|
|
||||||
var outletID *uuid.UUID
|
poResponse, err := s.purchaseOrderProcessor.UpdatePurchaseOrder(ctx, id, apctx.OrganizationID, modelReq)
|
||||||
if apctx.OutletID != uuid.Nil {
|
|
||||||
outletID = &apctx.OutletID
|
|
||||||
}
|
|
||||||
|
|
||||||
poResponse, err := s.purchaseOrderProcessor.UpdatePurchaseOrder(ctx, id, apctx.OrganizationID, outletID, modelReq)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
|
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
|
||||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||||
|
|||||||
@ -120,7 +120,6 @@ func PurchaseOrderModelResponseToResponse(po *models.PurchaseOrderResponse) *con
|
|||||||
response := &contract.PurchaseOrderResponse{
|
response := &contract.PurchaseOrderResponse{
|
||||||
ID: po.ID,
|
ID: po.ID,
|
||||||
OrganizationID: po.OrganizationID,
|
OrganizationID: po.OrganizationID,
|
||||||
OutletID: po.OutletID,
|
|
||||||
VendorID: po.VendorID,
|
VendorID: po.VendorID,
|
||||||
PONumber: po.PONumber,
|
PONumber: po.PONumber,
|
||||||
TransactionDate: po.TransactionDate,
|
TransactionDate: po.TransactionDate,
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
DROP INDEX IF EXISTS idx_purchase_orders_outlet_id;
|
|
||||||
|
|
||||||
ALTER TABLE purchase_orders
|
|
||||||
DROP COLUMN IF EXISTS outlet_id;
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
ALTER TABLE purchase_orders
|
|
||||||
ADD COLUMN IF NOT EXISTS outlet_id UUID REFERENCES outlets(id) ON DELETE SET NULL;
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_purchase_orders_outlet_id
|
|
||||||
ON purchase_orders(outlet_id);
|
|
||||||
|
|
||||||
WITH movement_outlets AS (
|
|
||||||
SELECT
|
|
||||||
poi.purchase_order_id,
|
|
||||||
MIN(im.outlet_id) AS outlet_id
|
|
||||||
FROM inventory_movements im
|
|
||||||
JOIN purchase_order_items poi ON im.purchase_order_item_id = poi.id
|
|
||||||
WHERE im.outlet_id IS NOT NULL
|
|
||||||
AND im.purchase_order_item_id IS NOT NULL
|
|
||||||
GROUP BY poi.purchase_order_id
|
|
||||||
HAVING COUNT(DISTINCT im.outlet_id) = 1
|
|
||||||
)
|
|
||||||
UPDATE purchase_orders po
|
|
||||||
SET outlet_id = movement_outlets.outlet_id
|
|
||||||
FROM movement_outlets
|
|
||||||
WHERE po.id = movement_outlets.purchase_order_id
|
|
||||||
AND po.outlet_id IS NULL;
|
|
||||||
|
|
||||||
WITH candidate_item_outlets AS (
|
|
||||||
SELECT
|
|
||||||
poi.purchase_order_id,
|
|
||||||
i.outlet_id
|
|
||||||
FROM purchase_order_items poi
|
|
||||||
JOIN ingredients i ON poi.ingredient_id = i.id
|
|
||||||
WHERE i.outlet_id IS NOT NULL
|
|
||||||
|
|
||||||
UNION ALL
|
|
||||||
|
|
||||||
SELECT
|
|
||||||
poi.purchase_order_id,
|
|
||||||
u.outlet_id
|
|
||||||
FROM purchase_order_items poi
|
|
||||||
JOIN units u ON poi.unit_id = u.id
|
|
||||||
WHERE u.outlet_id IS NOT NULL
|
|
||||||
), item_outlets AS (
|
|
||||||
SELECT
|
|
||||||
purchase_order_id,
|
|
||||||
MIN(outlet_id) AS outlet_id
|
|
||||||
FROM candidate_item_outlets
|
|
||||||
GROUP BY purchase_order_id
|
|
||||||
HAVING COUNT(DISTINCT outlet_id) = 1
|
|
||||||
)
|
|
||||||
UPDATE purchase_orders po
|
|
||||||
SET outlet_id = item_outlets.outlet_id
|
|
||||||
FROM item_outlets
|
|
||||||
WHERE po.id = item_outlets.purchase_order_id
|
|
||||||
AND po.outlet_id IS NULL;
|
|
||||||
|
|
||||||
WITH single_outlet_organizations AS (
|
|
||||||
SELECT
|
|
||||||
organization_id,
|
|
||||||
MIN(id) AS outlet_id
|
|
||||||
FROM outlets
|
|
||||||
GROUP BY organization_id
|
|
||||||
HAVING COUNT(*) = 1
|
|
||||||
)
|
|
||||||
UPDATE purchase_orders po
|
|
||||||
SET outlet_id = single_outlet_organizations.outlet_id
|
|
||||||
FROM single_outlet_organizations
|
|
||||||
WHERE po.organization_id = single_outlet_organizations.organization_id
|
|
||||||
AND po.outlet_id IS NULL;
|
|
||||||
Loading…
x
Reference in New Issue
Block a user