Merge branch 'main' of https://gits.altru.id/apksel-dev/apskel-pos-backend
This commit is contained in:
@@ -433,38 +433,40 @@ func (r *AnalyticsRepositoryImpl) GetDashboardOverview(ctx context.Context, orga
|
||||
}
|
||||
|
||||
func (r *AnalyticsRepositoryImpl) GetProfitLossAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, groupBy string) (*entities.ProfitLossAnalytics, error) {
|
||||
// Summary query
|
||||
var summary entities.ProfitLossSummary
|
||||
mtdStart := time.Date(dateTo.Year(), dateTo.Month(), 1, 0, 0, 0, 0, dateTo.Location())
|
||||
todayStart := time.Date(dateTo.Year(), dateTo.Month(), dateTo.Day(), 0, 0, 0, 0, dateTo.Location())
|
||||
todayEnd := todayStart.Add(24 * time.Hour).Add(-time.Nanosecond)
|
||||
|
||||
var summary entities.ProfitLossSummary
|
||||
summaryQuery := r.db.WithContext(ctx).
|
||||
Table("orders o").
|
||||
Select(`
|
||||
COALESCE(SUM(o.total_amount), 0) as total_revenue,
|
||||
COALESCE(SUM(o.total_cost), 0) as total_cost,
|
||||
COALESCE(SUM(o.total_amount - o.total_cost), 0) as gross_profit,
|
||||
CASE
|
||||
WHEN SUM(o.total_amount) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost) / SUM(o.total_amount)) * 100
|
||||
ELSE 0
|
||||
CASE
|
||||
WHEN SUM(o.total_amount) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost) / SUM(o.total_amount)) * 100
|
||||
ELSE 0
|
||||
END as gross_profit_margin,
|
||||
COALESCE(SUM(o.tax_amount), 0) as total_tax,
|
||||
COALESCE(SUM(o.discount_amount), 0) as total_discount,
|
||||
COALESCE(SUM(o.total_amount - o.total_cost - o.discount_amount), 0) as net_profit,
|
||||
CASE
|
||||
WHEN SUM(o.total_amount) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost - o.discount_amount) / SUM(o.total_amount)) * 100
|
||||
ELSE 0
|
||||
CASE
|
||||
WHEN SUM(o.total_amount) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost - o.discount_amount) / SUM(o.total_amount)) * 100
|
||||
ELSE 0
|
||||
END as net_profit_margin,
|
||||
COUNT(o.id) as total_orders,
|
||||
CASE
|
||||
WHEN COUNT(o.id) > 0
|
||||
THEN SUM(o.total_amount - o.total_cost - o.discount_amount) / COUNT(o.id)
|
||||
ELSE 0
|
||||
CASE
|
||||
WHEN COUNT(o.id) > 0
|
||||
THEN SUM(o.total_amount - o.total_cost - o.discount_amount) / COUNT(o.id)
|
||||
ELSE 0
|
||||
END as average_profit,
|
||||
CASE
|
||||
WHEN SUM(o.total_cost) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost) / SUM(o.total_cost)) * 100
|
||||
ELSE 0
|
||||
CASE
|
||||
WHEN SUM(o.total_cost) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost) / SUM(o.total_cost)) * 100
|
||||
ELSE 0
|
||||
END as profitability_ratio
|
||||
`).
|
||||
Where("o.organization_id = ?", organizationID).
|
||||
@@ -472,15 +474,11 @@ func (r *AnalyticsRepositoryImpl) GetProfitLossAnalytics(ctx context.Context, or
|
||||
Where("o.payment_status = ?", entities.PaymentStatusCompleted).
|
||||
Where("o.is_void = false AND o.is_refund = false").
|
||||
Where("o.created_at >= ? AND o.created_at <= ?", dateFrom, dateTo)
|
||||
|
||||
summaryQuery = r.resolveOutletID(summaryQuery, outletID, "o.outlet_id")
|
||||
|
||||
err := summaryQuery.Scan(&summary).Error
|
||||
if err != nil {
|
||||
if err := summaryQuery.Scan(&summary).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Time series data query
|
||||
var timeFormat string
|
||||
switch groupBy {
|
||||
case "hour":
|
||||
@@ -489,12 +487,11 @@ func (r *AnalyticsRepositoryImpl) GetProfitLossAnalytics(ctx context.Context, or
|
||||
timeFormat = "DATE_TRUNC('week', o.created_at)"
|
||||
case "month":
|
||||
timeFormat = "DATE_TRUNC('month', o.created_at)"
|
||||
default: // day
|
||||
default:
|
||||
timeFormat = "DATE_TRUNC('day', o.created_at)"
|
||||
}
|
||||
|
||||
var data []entities.ProfitLossData
|
||||
|
||||
dataQuery := r.db.WithContext(ctx).
|
||||
Table("orders o").
|
||||
Select(`
|
||||
@@ -502,18 +499,18 @@ func (r *AnalyticsRepositoryImpl) GetProfitLossAnalytics(ctx context.Context, or
|
||||
COALESCE(SUM(o.total_amount), 0) as revenue,
|
||||
COALESCE(SUM(o.total_cost), 0) as cost,
|
||||
COALESCE(SUM(o.total_amount - o.total_cost), 0) as gross_profit,
|
||||
CASE
|
||||
WHEN SUM(o.total_amount) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost) / SUM(o.total_amount)) * 100
|
||||
ELSE 0
|
||||
CASE
|
||||
WHEN SUM(o.total_amount) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost) / SUM(o.total_amount)) * 100
|
||||
ELSE 0
|
||||
END as gross_profit_margin,
|
||||
COALESCE(SUM(o.tax_amount), 0) as tax,
|
||||
COALESCE(SUM(o.discount_amount), 0) as discount,
|
||||
COALESCE(SUM(o.total_amount - o.total_cost - o.discount_amount), 0) as net_profit,
|
||||
CASE
|
||||
WHEN SUM(o.total_amount) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost - o.discount_amount) / SUM(o.total_amount)) * 100
|
||||
ELSE 0
|
||||
CASE
|
||||
WHEN SUM(o.total_amount) > 0
|
||||
THEN (SUM(o.total_amount - o.total_cost - o.discount_amount) / SUM(o.total_amount)) * 100
|
||||
ELSE 0
|
||||
END as net_profit_margin,
|
||||
COUNT(o.id) as orders
|
||||
`).
|
||||
@@ -524,17 +521,12 @@ func (r *AnalyticsRepositoryImpl) GetProfitLossAnalytics(ctx context.Context, or
|
||||
Where("o.created_at >= ? AND o.created_at <= ?", dateFrom, dateTo).
|
||||
Group(timeFormat).
|
||||
Order(timeFormat)
|
||||
|
||||
dataQuery = r.resolveOutletID(dataQuery, outletID, "o.outlet_id")
|
||||
|
||||
err = dataQuery.Scan(&data).Error
|
||||
if err != nil {
|
||||
if err := dataQuery.Scan(&data).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Product profit data query
|
||||
var productData []entities.ProductProfitData
|
||||
|
||||
productQuery := r.db.WithContext(ctx).
|
||||
Table("order_items oi").
|
||||
Select(`
|
||||
@@ -546,10 +538,10 @@ func (r *AnalyticsRepositoryImpl) GetProfitLossAnalytics(ctx context.Context, or
|
||||
SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END) as revenue,
|
||||
SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_cost * ((oi.quantity - COALESCE(oi.refund_quantity, 0))::float / NULLIF(oi.quantity, 0)) ELSE 0 END) as cost,
|
||||
SUM(CASE WHEN oi.is_fully_refunded = false THEN (oi.total_price - COALESCE(oi.refund_amount, 0)) - (oi.total_cost * ((oi.quantity - COALESCE(oi.refund_quantity, 0))::float / NULLIF(oi.quantity, 0))) ELSE 0 END) as gross_profit,
|
||||
CASE
|
||||
WHEN SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END) > 0
|
||||
THEN (SUM(CASE WHEN oi.is_fully_refunded = false THEN (oi.total_price - COALESCE(oi.refund_amount, 0)) - (oi.total_cost * ((oi.quantity - COALESCE(oi.refund_quantity, 0))::float / NULLIF(oi.quantity, 0))) ELSE 0 END) / SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END)) * 100
|
||||
ELSE 0
|
||||
CASE
|
||||
WHEN SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END) > 0
|
||||
THEN (SUM(CASE WHEN oi.is_fully_refunded = false THEN (oi.total_price - COALESCE(oi.refund_amount, 0)) - (oi.total_cost * ((oi.quantity - COALESCE(oi.refund_quantity, 0))::float / NULLIF(oi.quantity, 0))) ELSE 0 END) / SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END)) * 100
|
||||
ELSE 0
|
||||
END as gross_profit_margin,
|
||||
AVG(CASE WHEN oi.is_fully_refunded = false THEN oi.unit_price ELSE NULL END) as average_price,
|
||||
AVG(CASE WHEN oi.is_fully_refunded = false THEN oi.unit_cost ELSE NULL END) as average_cost,
|
||||
@@ -567,17 +559,124 @@ func (r *AnalyticsRepositoryImpl) GetProfitLossAnalytics(ctx context.Context, or
|
||||
Group("p.id, p.name, c.id, c.name").
|
||||
Order("p.name ASC").
|
||||
Limit(1000)
|
||||
|
||||
productQuery = r.resolveOutletID(productQuery, outletID, "o.outlet_id")
|
||||
if err := productQuery.Scan(&productData).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = productQuery.Scan(&productData).Error
|
||||
type revenueCostResult struct {
|
||||
Revenue float64
|
||||
Cost float64
|
||||
}
|
||||
|
||||
var todayRC revenueCostResult
|
||||
todayQuery := r.db.WithContext(ctx).
|
||||
Table("orders o").
|
||||
Select(`
|
||||
COALESCE(SUM(o.total_amount), 0) as revenue,
|
||||
COALESCE(SUM(o.total_cost), 0) as cost
|
||||
`).
|
||||
Where("o.organization_id = ?", organizationID).
|
||||
Where("o.status = ?", entities.OrderStatusCompleted).
|
||||
Where("o.payment_status = ?", entities.PaymentStatusCompleted).
|
||||
Where("o.is_void = false AND o.is_refund = false").
|
||||
Where("o.created_at >= ? AND o.created_at <= ?", todayStart, todayEnd)
|
||||
todayQuery = r.resolveOutletID(todayQuery, outletID, "o.outlet_id")
|
||||
if err := todayQuery.Scan(&todayRC).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mtdRC revenueCostResult
|
||||
mtdQuery := r.db.WithContext(ctx).
|
||||
Table("orders o").
|
||||
Select(`
|
||||
COALESCE(SUM(o.total_amount), 0) as revenue,
|
||||
COALESCE(SUM(o.total_cost), 0) as cost
|
||||
`).
|
||||
Where("o.organization_id = ?", organizationID).
|
||||
Where("o.status = ?", entities.OrderStatusCompleted).
|
||||
Where("o.payment_status = ?", entities.PaymentStatusCompleted).
|
||||
Where("o.is_void = false AND o.is_refund = false").
|
||||
Where("o.created_at >= ? AND o.created_at <= ?", mtdStart, todayEnd)
|
||||
mtdQuery = r.resolveOutletID(mtdQuery, outletID, "o.outlet_id")
|
||||
if err := mtdQuery.Scan(&mtdRC).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
todayExpenseByCategory, err := r.getExpenseByCategory(ctx, organizationID, outletID, todayStart, todayEnd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mtdExpenseByCategory, err := r.getExpenseByCategory(ctx, organizationID, outletID, mtdStart, todayEnd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opsItems, err := r.getOperationalExpenseItems(ctx, organizationID, outletID, mtdStart, todayEnd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &entities.ProfitLossAnalytics{
|
||||
Summary: summary,
|
||||
Data: data,
|
||||
ProductData: productData,
|
||||
Summary: summary,
|
||||
Data: data,
|
||||
ProductData: productData,
|
||||
TodayRevenue: todayRC.Revenue,
|
||||
TodayCost: todayRC.Cost,
|
||||
MtdRevenue: mtdRC.Revenue,
|
||||
MtdCost: mtdRC.Cost,
|
||||
TodayExpenseByCategory: todayExpenseByCategory,
|
||||
MtdExpenseByCategory: mtdExpenseByCategory,
|
||||
OperationalExpenseItems: opsItems,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *AnalyticsRepositoryImpl) getExpenseByCategory(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) ([]entities.ExpenseCategoryTotal, error) {
|
||||
var results []entities.ExpenseCategoryTotal
|
||||
|
||||
query := r.db.WithContext(ctx).
|
||||
Table("expense_items ei").
|
||||
Select(`COALESCE(parent_coa.name, 'Lain-lain') as category_name, COALESCE(SUM(ei.amount), 0) as amount`).
|
||||
Joins("JOIN expenses e ON ei.expense_id = e.id").
|
||||
Joins("JOIN chart_of_accounts coa ON ei.chart_of_account_id = coa.id").
|
||||
Joins("LEFT JOIN chart_of_accounts parent_coa ON coa.parent_id = parent_coa.id").
|
||||
Where("e.organization_id = ?", organizationID).
|
||||
Where("e.status = ?", "approved").
|
||||
Where("e.transaction_date >= ? AND e.transaction_date <= ?", dateFrom, dateTo)
|
||||
|
||||
if outletID != nil {
|
||||
query = query.Where("e.outlet_id = ?", *outletID)
|
||||
}
|
||||
|
||||
err := query.
|
||||
Group("parent_coa.name").
|
||||
Order("parent_coa.name").
|
||||
Scan(&results).Error
|
||||
|
||||
return results, err
|
||||
}
|
||||
|
||||
func (r *AnalyticsRepositoryImpl) getOperationalExpenseItems(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) ([]entities.OperationalExpenseItem, error) {
|
||||
var results []entities.OperationalExpenseItem
|
||||
|
||||
query := r.db.WithContext(ctx).
|
||||
Table("expense_items ei").
|
||||
Select(`COALESCE(NULLIF(ei.item, ''), ei.description, coa.name) as item, COALESCE(SUM(ei.amount), 0) as amount`).
|
||||
Joins("JOIN expenses e ON ei.expense_id = e.id").
|
||||
Joins("JOIN chart_of_accounts coa ON ei.chart_of_account_id = coa.id").
|
||||
Where("e.organization_id = ?", organizationID).
|
||||
Where("e.status = ?", "approved").
|
||||
Where("e.transaction_date >= ? AND e.transaction_date <= ?", dateFrom, dateTo)
|
||||
|
||||
if outletID != nil {
|
||||
query = query.Where("e.outlet_id = ?", *outletID)
|
||||
}
|
||||
|
||||
err := query.
|
||||
Group("COALESCE(NULLIF(ei.item, ''), ei.description, coa.name)").
|
||||
Order("amount DESC").
|
||||
Scan(&results).Error
|
||||
|
||||
return results, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"apskel-pos-be/internal/entities"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ExpenseRepositoryImpl struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewExpenseRepositoryImpl(db *gorm.DB) *ExpenseRepositoryImpl {
|
||||
return &ExpenseRepositoryImpl{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ExpenseRepositoryImpl) Create(ctx context.Context, expense *entities.Expense) error {
|
||||
return r.db.WithContext(ctx).Create(expense).Error
|
||||
}
|
||||
|
||||
func (r *ExpenseRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.Expense, error) {
|
||||
var expense entities.Expense
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Items.ChartOfAccount").
|
||||
First(&expense, "id = ?", id).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &expense, nil
|
||||
}
|
||||
|
||||
func (r *ExpenseRepositoryImpl) GetByIDAndOrganizationID(ctx context.Context, id, organizationID uuid.UUID) (*entities.Expense, error) {
|
||||
var expense entities.Expense
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Items.ChartOfAccount").
|
||||
Where("id = ? AND organization_id = ?", id, organizationID).
|
||||
First(&expense).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &expense, nil
|
||||
}
|
||||
|
||||
func (r *ExpenseRepositoryImpl) Update(ctx context.Context, expense *entities.Expense) error {
|
||||
return r.db.WithContext(ctx).Save(expense).Error
|
||||
}
|
||||
|
||||
func (r *ExpenseRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.Expense{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
func (r *ExpenseRepositoryImpl) List(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, limit, offset int) ([]*entities.Expense, int64, error) {
|
||||
var expenses []*entities.Expense
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.Expense{}).Where("organization_id = ?", organizationID)
|
||||
|
||||
for key, value := range filters {
|
||||
switch key {
|
||||
case "search":
|
||||
if searchStr, ok := value.(string); ok && searchStr != "" {
|
||||
searchPattern := "%" + strings.ToLower(searchStr) + "%"
|
||||
query = query.Where(`
|
||||
LOWER(receiver) LIKE ?
|
||||
OR LOWER(code_number) LIKE ?
|
||||
OR LOWER(description) LIKE ?
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM expense_items ei
|
||||
WHERE ei.expense_id = expenses.id
|
||||
AND LOWER(ei.item) LIKE ?
|
||||
)
|
||||
`, searchPattern, searchPattern, searchPattern, searchPattern)
|
||||
}
|
||||
case "outlet_id":
|
||||
if outletID, ok := value.(uuid.UUID); ok {
|
||||
query = query.Where("outlet_id = ?", outletID)
|
||||
}
|
||||
case "status":
|
||||
if status, ok := value.(string); ok && status != "" {
|
||||
query = query.Where("status = ?", status)
|
||||
}
|
||||
case "start_date":
|
||||
if startDate, ok := value.(time.Time); ok {
|
||||
query = query.Where("transaction_date >= ?", startDate)
|
||||
}
|
||||
case "end_date":
|
||||
if endDate, ok := value.(time.Time); ok {
|
||||
query = query.Where("transaction_date <= ?", endDate)
|
||||
}
|
||||
default:
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
err := query.
|
||||
Preload("Items.ChartOfAccount").
|
||||
Order("created_at DESC").
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Find(&expenses).Error
|
||||
return expenses, total, err
|
||||
}
|
||||
|
||||
func (r *ExpenseRepositoryImpl) CreateItem(ctx context.Context, item *entities.ExpenseItem) error {
|
||||
return r.db.WithContext(ctx).Create(item).Error
|
||||
}
|
||||
|
||||
func (r *ExpenseRepositoryImpl) DeleteItemsByExpenseID(ctx context.Context, expenseID uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.ExpenseItem{}, "expense_id = ?", expenseID).Error
|
||||
}
|
||||
@@ -61,6 +61,7 @@ func (r *OrderRepositoryImpl) GetWithRelations(ctx context.Context, id uuid.UUID
|
||||
Preload("OrderItems").
|
||||
Preload("OrderItems.Product").
|
||||
Preload("OrderItems.Product.Category").
|
||||
Preload("OrderItems.Product.ProductOutletPrices").
|
||||
Preload("OrderItems.ProductVariant").
|
||||
Preload("Payments").
|
||||
Preload("Payments.PaymentMethod").
|
||||
@@ -141,6 +142,7 @@ func (r *OrderRepositoryImpl) List(ctx context.Context, filters map[string]inter
|
||||
Preload("OrderItems").
|
||||
Preload("OrderItems.Product").
|
||||
Preload("OrderItems.Product.Category").
|
||||
Preload("OrderItems.Product.ProductOutletPrices").
|
||||
Preload("OrderItems.ProductVariant").
|
||||
Preload("Payments").
|
||||
Preload("Payments.PaymentMethod").
|
||||
@@ -158,6 +160,7 @@ func (r *OrderRepositoryImpl) ListBySessionID(ctx context.Context, sessionID str
|
||||
Preload("OrderItems").
|
||||
Preload("OrderItems.Product").
|
||||
Preload("OrderItems.Product.Category").
|
||||
Preload("OrderItems.Product.ProductOutletPrices").
|
||||
Preload("OrderItems.ProductVariant").
|
||||
Preload("Payments").
|
||||
Preload("Payments.PaymentMethod").
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type ProductOutletPriceRepository interface {
|
||||
@@ -53,10 +52,18 @@ func (r *ProductOutletPriceRepositoryImpl) GetByOutlet(ctx context.Context, outl
|
||||
}
|
||||
|
||||
func (r *ProductOutletPriceRepositoryImpl) Upsert(ctx context.Context, price *entities.ProductOutletPrice) error {
|
||||
return r.db.WithContext(ctx).Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "product_id"}, {Name: "outlet_id"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"price", "updated_at"}),
|
||||
}).Create(price).Error
|
||||
if price.ID == uuid.Nil {
|
||||
price.ID = uuid.New()
|
||||
}
|
||||
return r.db.WithContext(ctx).Exec(`
|
||||
INSERT INTO product_outlet_prices (id, product_id, outlet_id, price, print_to_checker, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, NOW(), NOW())
|
||||
ON CONFLICT (product_id, outlet_id)
|
||||
DO UPDATE SET
|
||||
price = EXCLUDED.price,
|
||||
print_to_checker = EXCLUDED.print_to_checker,
|
||||
updated_at = NOW()
|
||||
`, price.ID, price.ProductID, price.OutletID, price.Price, price.PrintToChecker).Error
|
||||
}
|
||||
|
||||
func (r *ProductOutletPriceRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
|
||||
Reference in New Issue
Block a user