259 lines
6.1 KiB
Go
259 lines
6.1 KiB
Go
|
|
package repository
|
||
|
|
|
||
|
|
import (
|
||
|
|
"apskel-pos-be/internal/entities"
|
||
|
|
"context"
|
||
|
|
"database/sql"
|
||
|
|
"fmt"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
)
|
||
|
|
|
||
|
|
type IngredientRepository struct {
|
||
|
|
db *sql.DB
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewIngredientRepository(db *sql.DB) *IngredientRepository {
|
||
|
|
return &IngredientRepository{db: db}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *IngredientRepository) Create(ctx context.Context, ingredient *entities.Ingredient) error {
|
||
|
|
query := `
|
||
|
|
INSERT INTO ingredients (id, organization_id, outlet_id, name, unit_id, cost, stock, is_semi_finished, is_active, metadata, created_at, updated_at)
|
||
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||
|
|
`
|
||
|
|
|
||
|
|
_, err := r.db.ExecContext(ctx, query,
|
||
|
|
ingredient.ID,
|
||
|
|
ingredient.OrganizationID,
|
||
|
|
ingredient.OutletID,
|
||
|
|
ingredient.Name,
|
||
|
|
ingredient.UnitID,
|
||
|
|
ingredient.Cost,
|
||
|
|
ingredient.Stock,
|
||
|
|
ingredient.IsSemiFinished,
|
||
|
|
ingredient.IsActive,
|
||
|
|
ingredient.Metadata,
|
||
|
|
ingredient.CreatedAt,
|
||
|
|
ingredient.UpdatedAt,
|
||
|
|
)
|
||
|
|
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *IngredientRepository) GetByID(ctx context.Context, id, organizationID uuid.UUID) (*entities.Ingredient, error) {
|
||
|
|
query := `
|
||
|
|
SELECT i.id, i.organization_id, i.outlet_id, i.name, i.unit_id, i.cost, i.stock, i.is_semi_finished, i.is_active, i.metadata, i.created_at, i.updated_at,
|
||
|
|
u.id, u.organization_id, u.outlet_id, u.name, u.abbreviation, u.is_active, u.created_at, u.updated_at
|
||
|
|
FROM ingredients i
|
||
|
|
LEFT JOIN units u ON i.unit_id = u.id
|
||
|
|
WHERE i.id = $1 AND i.organization_id = $2
|
||
|
|
`
|
||
|
|
|
||
|
|
ingredient := &entities.Ingredient{}
|
||
|
|
unit := &entities.Unit{}
|
||
|
|
|
||
|
|
err := r.db.QueryRowContext(ctx, query, id, organizationID).Scan(
|
||
|
|
&ingredient.ID,
|
||
|
|
&ingredient.OrganizationID,
|
||
|
|
&ingredient.OutletID,
|
||
|
|
&ingredient.Name,
|
||
|
|
&ingredient.UnitID,
|
||
|
|
&ingredient.Cost,
|
||
|
|
&ingredient.Stock,
|
||
|
|
&ingredient.IsSemiFinished,
|
||
|
|
&ingredient.IsActive,
|
||
|
|
&ingredient.Metadata,
|
||
|
|
&ingredient.CreatedAt,
|
||
|
|
&ingredient.UpdatedAt,
|
||
|
|
&unit.ID,
|
||
|
|
&unit.OrganizationID,
|
||
|
|
&unit.OutletID,
|
||
|
|
&unit.Name,
|
||
|
|
&unit.Abbreviation,
|
||
|
|
&unit.IsActive,
|
||
|
|
&unit.CreatedAt,
|
||
|
|
&unit.UpdatedAt,
|
||
|
|
)
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
ingredient.Unit = unit
|
||
|
|
return ingredient, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *IngredientRepository) GetAll(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, page, limit int, search string, isSemiFinished *bool) ([]*entities.Ingredient, int, error) {
|
||
|
|
offset := (page - 1) * limit
|
||
|
|
|
||
|
|
// Build WHERE clause
|
||
|
|
whereClause := "WHERE i.organization_id = $1"
|
||
|
|
args := []interface{}{organizationID}
|
||
|
|
argCount := 1
|
||
|
|
|
||
|
|
if outletID != nil {
|
||
|
|
argCount++
|
||
|
|
whereClause += fmt.Sprintf(" AND i.outlet_id = $%d", argCount)
|
||
|
|
args = append(args, *outletID)
|
||
|
|
}
|
||
|
|
|
||
|
|
if search != "" {
|
||
|
|
argCount++
|
||
|
|
whereClause += fmt.Sprintf(" AND i.name ILIKE $%d", argCount)
|
||
|
|
args = append(args, "%"+search+"%")
|
||
|
|
}
|
||
|
|
|
||
|
|
if isSemiFinished != nil {
|
||
|
|
argCount++
|
||
|
|
whereClause += fmt.Sprintf(" AND i.is_semi_finished = $%d", argCount)
|
||
|
|
args = append(args, *isSemiFinished)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Count query
|
||
|
|
countQuery := fmt.Sprintf("SELECT COUNT(*) FROM ingredients i %s", whereClause)
|
||
|
|
var total int
|
||
|
|
err := r.db.QueryRowContext(ctx, countQuery, args...).Scan(&total)
|
||
|
|
if err != nil {
|
||
|
|
return nil, 0, err
|
||
|
|
}
|
||
|
|
|
||
|
|
// Data query
|
||
|
|
argCount++
|
||
|
|
query := fmt.Sprintf(`
|
||
|
|
SELECT i.id, i.organization_id, i.outlet_id, i.name, i.unit_id, i.cost, i.stock, i.is_semi_finished, i.is_active, i.metadata, i.created_at, i.updated_at,
|
||
|
|
u.id, u.organization_id, u.outlet_id, u.name, u.abbreviation, u.is_active, u.created_at, u.updated_at
|
||
|
|
FROM ingredients i
|
||
|
|
LEFT JOIN units u ON i.unit_id = u.id
|
||
|
|
%s
|
||
|
|
ORDER BY i.created_at DESC
|
||
|
|
LIMIT $%d OFFSET $%d
|
||
|
|
`, whereClause, argCount, argCount+1)
|
||
|
|
|
||
|
|
args = append(args, limit, offset)
|
||
|
|
|
||
|
|
rows, err := r.db.QueryContext(ctx, query, args...)
|
||
|
|
if err != nil {
|
||
|
|
return nil, 0, err
|
||
|
|
}
|
||
|
|
defer rows.Close()
|
||
|
|
|
||
|
|
var ingredients []*entities.Ingredient
|
||
|
|
for rows.Next() {
|
||
|
|
ingredient := &entities.Ingredient{}
|
||
|
|
unit := &entities.Unit{}
|
||
|
|
|
||
|
|
err := rows.Scan(
|
||
|
|
&ingredient.ID,
|
||
|
|
&ingredient.OrganizationID,
|
||
|
|
&ingredient.OutletID,
|
||
|
|
&ingredient.Name,
|
||
|
|
&ingredient.UnitID,
|
||
|
|
&ingredient.Cost,
|
||
|
|
&ingredient.Stock,
|
||
|
|
&ingredient.IsSemiFinished,
|
||
|
|
&ingredient.IsActive,
|
||
|
|
&ingredient.Metadata,
|
||
|
|
&ingredient.CreatedAt,
|
||
|
|
&ingredient.UpdatedAt,
|
||
|
|
&unit.ID,
|
||
|
|
&unit.OrganizationID,
|
||
|
|
&unit.OutletID,
|
||
|
|
&unit.Name,
|
||
|
|
&unit.Abbreviation,
|
||
|
|
&unit.IsActive,
|
||
|
|
&unit.CreatedAt,
|
||
|
|
&unit.UpdatedAt,
|
||
|
|
)
|
||
|
|
if err != nil {
|
||
|
|
return nil, 0, err
|
||
|
|
}
|
||
|
|
|
||
|
|
ingredient.Unit = unit
|
||
|
|
ingredients = append(ingredients, ingredient)
|
||
|
|
}
|
||
|
|
|
||
|
|
return ingredients, total, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *IngredientRepository) Update(ctx context.Context, ingredient *entities.Ingredient) error {
|
||
|
|
query := `
|
||
|
|
UPDATE ingredients
|
||
|
|
SET outlet_id = $1, name = $2, unit_id = $3, cost = $4, stock = $5, is_semi_finished = $6, is_active = $7, metadata = $8, updated_at = $9
|
||
|
|
WHERE id = $10 AND organization_id = $11
|
||
|
|
`
|
||
|
|
|
||
|
|
result, err := r.db.ExecContext(ctx, query,
|
||
|
|
ingredient.OutletID,
|
||
|
|
ingredient.Name,
|
||
|
|
ingredient.UnitID,
|
||
|
|
ingredient.Cost,
|
||
|
|
ingredient.Stock,
|
||
|
|
ingredient.IsSemiFinished,
|
||
|
|
ingredient.IsActive,
|
||
|
|
ingredient.Metadata,
|
||
|
|
ingredient.UpdatedAt,
|
||
|
|
ingredient.ID,
|
||
|
|
ingredient.OrganizationID,
|
||
|
|
)
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
rowsAffected, err := result.RowsAffected()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
if rowsAffected == 0 {
|
||
|
|
return sql.ErrNoRows
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *IngredientRepository) UpdateStock(ctx context.Context, id uuid.UUID, quantity float64, organizationID uuid.UUID) error {
|
||
|
|
query := `
|
||
|
|
UPDATE ingredients
|
||
|
|
SET stock = stock + $1, updated_at = NOW()
|
||
|
|
WHERE id = $2 AND organization_id = $3
|
||
|
|
`
|
||
|
|
|
||
|
|
result, err := r.db.ExecContext(ctx, query, quantity, id, organizationID)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
rowsAffected, err := result.RowsAffected()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
if rowsAffected == 0 {
|
||
|
|
return sql.ErrNoRows
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *IngredientRepository) Delete(ctx context.Context, id, organizationID uuid.UUID) error {
|
||
|
|
query := `DELETE FROM ingredients WHERE id = $1 AND organization_id = $2`
|
||
|
|
|
||
|
|
result, err := r.db.ExecContext(ctx, query, id, organizationID)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
rowsAffected, err := result.RowsAffected()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
if rowsAffected == 0 {
|
||
|
|
return sql.ErrNoRows
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|