Update users
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type IngredientCompositionRepository struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewIngredientCompositionRepository(db *sql.DB) *IngredientCompositionRepository {
|
||||
return &IngredientCompositionRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *IngredientCompositionRepository) Create(ctx context.Context, composition *entities.IngredientComposition) error {
|
||||
query := `
|
||||
INSERT INTO ingredient_compositions (id, organization_id, outlet_id, parent_ingredient_id, child_ingredient_id, quantity, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
`
|
||||
|
||||
_, err := r.db.ExecContext(ctx, query,
|
||||
composition.ID,
|
||||
composition.OrganizationID,
|
||||
composition.OutletID,
|
||||
composition.ParentIngredientID,
|
||||
composition.ChildIngredientID,
|
||||
composition.Quantity,
|
||||
composition.CreatedAt,
|
||||
composition.UpdatedAt,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *IngredientCompositionRepository) GetByID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientComposition, error) {
|
||||
query := `
|
||||
SELECT ic.id, ic.organization_id, ic.outlet_id, ic.parent_ingredient_id, ic.child_ingredient_id, ic.quantity, ic.created_at, ic.updated_at,
|
||||
pi.id, pi.organization_id, pi.outlet_id, pi.name, pi.unit_id, pi.cost, pi.stock, pi.is_semi_finished, pi.is_active, pi.metadata, pi.created_at, pi.updated_at,
|
||||
ci.id, ci.organization_id, ci.outlet_id, ci.name, ci.unit_id, ci.cost, ci.stock, ci.is_semi_finished, ci.is_active, ci.metadata, ci.created_at, ci.updated_at
|
||||
FROM ingredient_compositions ic
|
||||
LEFT JOIN ingredients pi ON ic.parent_ingredient_id = pi.id
|
||||
LEFT JOIN ingredients ci ON ic.child_ingredient_id = ci.id
|
||||
WHERE ic.id = $1 AND ic.organization_id = $2
|
||||
`
|
||||
|
||||
composition := &entities.IngredientComposition{}
|
||||
parentIngredient := &entities.Ingredient{}
|
||||
childIngredient := &entities.Ingredient{}
|
||||
|
||||
err := r.db.QueryRowContext(ctx, query, id, organizationID).Scan(
|
||||
&composition.ID,
|
||||
&composition.OrganizationID,
|
||||
&composition.OutletID,
|
||||
&composition.ParentIngredientID,
|
||||
&composition.ChildIngredientID,
|
||||
&composition.Quantity,
|
||||
&composition.CreatedAt,
|
||||
&composition.UpdatedAt,
|
||||
&parentIngredient.ID,
|
||||
&parentIngredient.OrganizationID,
|
||||
&parentIngredient.OutletID,
|
||||
&parentIngredient.Name,
|
||||
&parentIngredient.UnitID,
|
||||
&parentIngredient.Cost,
|
||||
&parentIngredient.Stock,
|
||||
&parentIngredient.IsSemiFinished,
|
||||
&parentIngredient.IsActive,
|
||||
&parentIngredient.Metadata,
|
||||
&parentIngredient.CreatedAt,
|
||||
&parentIngredient.UpdatedAt,
|
||||
&childIngredient.ID,
|
||||
&childIngredient.OrganizationID,
|
||||
&childIngredient.OutletID,
|
||||
&childIngredient.Name,
|
||||
&childIngredient.UnitID,
|
||||
&childIngredient.Cost,
|
||||
&childIngredient.Stock,
|
||||
&childIngredient.IsSemiFinished,
|
||||
&childIngredient.IsActive,
|
||||
&childIngredient.Metadata,
|
||||
&childIngredient.CreatedAt,
|
||||
&childIngredient.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
composition.ParentIngredient = parentIngredient
|
||||
composition.ChildIngredient = childIngredient
|
||||
return composition, nil
|
||||
}
|
||||
|
||||
func (r *IngredientCompositionRepository) GetByParentIngredientID(ctx context.Context, parentIngredientID, organizationID uuid.UUID) ([]*entities.IngredientComposition, error) {
|
||||
query := `
|
||||
SELECT ic.id, ic.organization_id, ic.outlet_id, ic.parent_ingredient_id, ic.child_ingredient_id, ic.quantity, ic.created_at, ic.updated_at,
|
||||
pi.id, pi.organization_id, pi.outlet_id, pi.name, pi.unit_id, pi.cost, pi.stock, pi.is_semi_finished, pi.is_active, pi.metadata, pi.created_at, pi.updated_at,
|
||||
ci.id, ci.organization_id, ci.outlet_id, ci.name, ci.unit_id, ci.cost, ci.stock, ci.is_semi_finished, ci.is_active, ci.metadata, ci.created_at, ci.updated_at
|
||||
FROM ingredient_compositions ic
|
||||
LEFT JOIN ingredients pi ON ic.parent_ingredient_id = pi.id
|
||||
LEFT JOIN ingredients ci ON ic.child_ingredient_id = ci.id
|
||||
WHERE ic.parent_ingredient_id = $1 AND ic.organization_id = $2
|
||||
ORDER BY ic.created_at DESC
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(ctx, query, parentIngredientID, organizationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var compositions []*entities.IngredientComposition
|
||||
for rows.Next() {
|
||||
composition := &entities.IngredientComposition{}
|
||||
parentIngredient := &entities.Ingredient{}
|
||||
childIngredient := &entities.Ingredient{}
|
||||
|
||||
err := rows.Scan(
|
||||
&composition.ID,
|
||||
&composition.OrganizationID,
|
||||
&composition.OutletID,
|
||||
&composition.ParentIngredientID,
|
||||
&composition.ChildIngredientID,
|
||||
&composition.Quantity,
|
||||
&composition.CreatedAt,
|
||||
&composition.UpdatedAt,
|
||||
&parentIngredient.ID,
|
||||
&parentIngredient.OrganizationID,
|
||||
&parentIngredient.OutletID,
|
||||
&parentIngredient.Name,
|
||||
&parentIngredient.UnitID,
|
||||
&parentIngredient.Cost,
|
||||
&parentIngredient.Stock,
|
||||
&parentIngredient.IsSemiFinished,
|
||||
&parentIngredient.IsActive,
|
||||
&parentIngredient.Metadata,
|
||||
&parentIngredient.CreatedAt,
|
||||
&parentIngredient.UpdatedAt,
|
||||
&childIngredient.ID,
|
||||
&childIngredient.OrganizationID,
|
||||
&childIngredient.OutletID,
|
||||
&childIngredient.Name,
|
||||
&childIngredient.UnitID,
|
||||
&childIngredient.Cost,
|
||||
&childIngredient.Stock,
|
||||
&childIngredient.IsSemiFinished,
|
||||
&childIngredient.IsActive,
|
||||
&childIngredient.Metadata,
|
||||
&childIngredient.CreatedAt,
|
||||
&childIngredient.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
composition.ParentIngredient = parentIngredient
|
||||
composition.ChildIngredient = childIngredient
|
||||
compositions = append(compositions, composition)
|
||||
}
|
||||
|
||||
return compositions, nil
|
||||
}
|
||||
|
||||
func (r *IngredientCompositionRepository) GetByChildIngredientID(ctx context.Context, childIngredientID, organizationID uuid.UUID) ([]*entities.IngredientComposition, error) {
|
||||
query := `
|
||||
SELECT ic.id, ic.organization_id, ic.outlet_id, ic.parent_ingredient_id, ic.child_ingredient_id, ic.quantity, ic.created_at, ic.updated_at,
|
||||
pi.id, pi.organization_id, pi.outlet_id, pi.name, pi.unit_id, pi.cost, pi.stock, pi.is_semi_finished, pi.is_active, pi.metadata, pi.created_at, pi.updated_at,
|
||||
ci.id, ci.organization_id, ci.outlet_id, ci.name, ci.unit_id, ci.cost, ci.stock, ci.is_semi_finished, ci.is_active, ci.metadata, ci.created_at, ci.updated_at
|
||||
FROM ingredient_compositions ic
|
||||
LEFT JOIN ingredients pi ON ic.parent_ingredient_id = pi.id
|
||||
LEFT JOIN ingredients ci ON ic.child_ingredient_id = ci.id
|
||||
WHERE ic.child_ingredient_id = $1 AND ic.organization_id = $2
|
||||
ORDER BY ic.created_at DESC
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(ctx, query, childIngredientID, organizationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var compositions []*entities.IngredientComposition
|
||||
for rows.Next() {
|
||||
composition := &entities.IngredientComposition{}
|
||||
parentIngredient := &entities.Ingredient{}
|
||||
childIngredient := &entities.Ingredient{}
|
||||
|
||||
err := rows.Scan(
|
||||
&composition.ID,
|
||||
&composition.OrganizationID,
|
||||
&composition.OutletID,
|
||||
&composition.ParentIngredientID,
|
||||
&composition.ChildIngredientID,
|
||||
&composition.Quantity,
|
||||
&composition.CreatedAt,
|
||||
&composition.UpdatedAt,
|
||||
&parentIngredient.ID,
|
||||
&parentIngredient.OrganizationID,
|
||||
&parentIngredient.OutletID,
|
||||
&parentIngredient.Name,
|
||||
&parentIngredient.UnitID,
|
||||
&parentIngredient.Cost,
|
||||
&parentIngredient.Stock,
|
||||
&parentIngredient.IsSemiFinished,
|
||||
&parentIngredient.IsActive,
|
||||
&parentIngredient.Metadata,
|
||||
&parentIngredient.CreatedAt,
|
||||
&parentIngredient.UpdatedAt,
|
||||
&childIngredient.ID,
|
||||
&childIngredient.OrganizationID,
|
||||
&childIngredient.OutletID,
|
||||
&childIngredient.Name,
|
||||
&childIngredient.UnitID,
|
||||
&childIngredient.Cost,
|
||||
&childIngredient.Stock,
|
||||
&childIngredient.IsSemiFinished,
|
||||
&childIngredient.IsActive,
|
||||
&childIngredient.Metadata,
|
||||
&childIngredient.CreatedAt,
|
||||
&childIngredient.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
composition.ParentIngredient = parentIngredient
|
||||
composition.ChildIngredient = childIngredient
|
||||
compositions = append(compositions, composition)
|
||||
}
|
||||
|
||||
return compositions, nil
|
||||
}
|
||||
|
||||
func (r *IngredientCompositionRepository) Update(ctx context.Context, composition *entities.IngredientComposition) error {
|
||||
query := `
|
||||
UPDATE ingredient_compositions
|
||||
SET outlet_id = $1, quantity = $2, updated_at = $3
|
||||
WHERE id = $4 AND organization_id = $5
|
||||
`
|
||||
|
||||
result, err := r.db.ExecContext(ctx, query,
|
||||
composition.OutletID,
|
||||
composition.Quantity,
|
||||
composition.UpdatedAt,
|
||||
composition.ID,
|
||||
composition.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 *IngredientCompositionRepository) Delete(ctx context.Context, id, organizationID uuid.UUID) error {
|
||||
query := `DELETE FROM ingredient_compositions 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
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
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
|
||||
}
|
||||
@@ -150,11 +150,12 @@ func (r *PaymentRepositoryImpl) CreatePaymentWithInventoryMovement(ctx context.C
|
||||
movement := &entities.InventoryMovement{
|
||||
OrganizationID: order.OrganizationID,
|
||||
OutletID: order.OutletID,
|
||||
ProductID: item.ProductID,
|
||||
ItemID: item.ProductID,
|
||||
ItemType: "PRODUCT",
|
||||
MovementType: entities.InventoryMovementTypeSale,
|
||||
Quantity: -item.Quantity,
|
||||
PreviousQuantity: updatedInventory.Quantity + item.Quantity, // Add back the quantity that was subtracted
|
||||
NewQuantity: updatedInventory.Quantity,
|
||||
Quantity: float64(-item.Quantity),
|
||||
PreviousQuantity: float64(updatedInventory.Quantity + item.Quantity), // Add back the quantity that was subtracted
|
||||
NewQuantity: float64(updatedInventory.Quantity),
|
||||
UnitCost: item.UnitCost,
|
||||
TotalCost: float64(item.Quantity) * item.UnitCost,
|
||||
ReferenceType: func() *entities.InventoryMovementReferenceType {
|
||||
@@ -222,11 +223,12 @@ func (r *PaymentRepositoryImpl) RefundPaymentWithInventoryMovement(ctx context.C
|
||||
movement := &entities.InventoryMovement{
|
||||
OrganizationID: order.OrganizationID,
|
||||
OutletID: order.OutletID,
|
||||
ProductID: item.ProductID,
|
||||
ItemID: item.ProductID,
|
||||
ItemType: "PRODUCT",
|
||||
MovementType: entities.InventoryMovementTypeRefund,
|
||||
Quantity: refundedQuantity,
|
||||
PreviousQuantity: updatedInventory.Quantity - refundedQuantity, // Subtract the quantity that was added
|
||||
NewQuantity: updatedInventory.Quantity,
|
||||
Quantity: float64(refundedQuantity),
|
||||
PreviousQuantity: float64(updatedInventory.Quantity - refundedQuantity), // Subtract the quantity that was added
|
||||
NewQuantity: float64(updatedInventory.Quantity),
|
||||
UnitCost: item.UnitCost,
|
||||
TotalCost: float64(refundedQuantity) * item.UnitCost,
|
||||
ReferenceType: func() *entities.InventoryMovementReferenceType {
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ProductIngredientRepository struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewProductIngredientRepository(db *sql.DB) *ProductIngredientRepository {
|
||||
return &ProductIngredientRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *ProductIngredientRepository) Create(ctx context.Context, productIngredient *entities.ProductIngredient) error {
|
||||
query := `
|
||||
INSERT INTO product_ingredients (id, organization_id, outlet_id, product_id, ingredient_id, quantity, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
`
|
||||
|
||||
_, err := r.db.ExecContext(ctx, query,
|
||||
productIngredient.ID,
|
||||
productIngredient.OrganizationID,
|
||||
productIngredient.OutletID,
|
||||
productIngredient.ProductID,
|
||||
productIngredient.IngredientID,
|
||||
productIngredient.Quantity,
|
||||
productIngredient.CreatedAt,
|
||||
productIngredient.UpdatedAt,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *ProductIngredientRepository) GetByID(ctx context.Context, id, organizationID uuid.UUID) (*entities.ProductIngredient, error) {
|
||||
query := `
|
||||
SELECT pi.id, pi.organization_id, pi.outlet_id, pi.product_id, pi.ingredient_id, pi.quantity, pi.created_at, pi.updated_at,
|
||||
p.id, p.organization_id, p.category_id, p.sku, p.name, p.description, p.price, p.cost, p.business_type, p.image_url, p.printer_type, p.unit_id, p.has_ingredients, p.metadata, p.is_active, p.created_at, p.updated_at,
|
||||
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
|
||||
FROM product_ingredients pi
|
||||
LEFT JOIN products p ON pi.product_id = p.id
|
||||
LEFT JOIN ingredients i ON pi.ingredient_id = i.id
|
||||
WHERE pi.id = $1 AND pi.organization_id = $2
|
||||
`
|
||||
|
||||
productIngredient := &entities.ProductIngredient{}
|
||||
product := &entities.Product{}
|
||||
ingredient := &entities.Ingredient{}
|
||||
|
||||
err := r.db.QueryRowContext(ctx, query, id, organizationID).Scan(
|
||||
&productIngredient.ID,
|
||||
&productIngredient.OrganizationID,
|
||||
&productIngredient.OutletID,
|
||||
&productIngredient.ProductID,
|
||||
&productIngredient.IngredientID,
|
||||
&productIngredient.Quantity,
|
||||
&productIngredient.CreatedAt,
|
||||
&productIngredient.UpdatedAt,
|
||||
&product.ID,
|
||||
&product.OrganizationID,
|
||||
&product.CategoryID,
|
||||
&product.SKU,
|
||||
&product.Name,
|
||||
&product.Description,
|
||||
&product.Price,
|
||||
&product.Cost,
|
||||
&product.BusinessType,
|
||||
&product.ImageURL,
|
||||
&product.PrinterType,
|
||||
&product.UnitID,
|
||||
&product.HasIngredients,
|
||||
&product.Metadata,
|
||||
&product.IsActive,
|
||||
&product.CreatedAt,
|
||||
&product.UpdatedAt,
|
||||
&ingredient.ID,
|
||||
&ingredient.OrganizationID,
|
||||
&ingredient.OutletID,
|
||||
&ingredient.Name,
|
||||
&ingredient.UnitID,
|
||||
&ingredient.Cost,
|
||||
&ingredient.Stock,
|
||||
&ingredient.IsSemiFinished,
|
||||
&ingredient.IsActive,
|
||||
&ingredient.Metadata,
|
||||
&ingredient.CreatedAt,
|
||||
&ingredient.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
productIngredient.Product = product
|
||||
productIngredient.Ingredient = ingredient
|
||||
return productIngredient, nil
|
||||
}
|
||||
|
||||
func (r *ProductIngredientRepository) GetByProductID(ctx context.Context, productID, organizationID uuid.UUID) ([]*entities.ProductIngredient, error) {
|
||||
query := `
|
||||
SELECT pi.id, pi.organization_id, pi.outlet_id, pi.product_id, pi.ingredient_id, pi.quantity, pi.created_at, pi.updated_at,
|
||||
p.id, p.organization_id, p.category_id, p.sku, p.name, p.description, p.price, p.cost, p.business_type, p.image_url, p.printer_type, p.unit_id, p.has_ingredients, p.metadata, p.is_active, p.created_at, p.updated_at,
|
||||
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
|
||||
FROM product_ingredients pi
|
||||
LEFT JOIN products p ON pi.product_id = p.id
|
||||
LEFT JOIN ingredients i ON pi.ingredient_id = i.id
|
||||
WHERE pi.product_id = $1 AND pi.organization_id = $2
|
||||
ORDER BY pi.created_at DESC
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(ctx, query, productID, organizationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var productIngredients []*entities.ProductIngredient
|
||||
for rows.Next() {
|
||||
productIngredient := &entities.ProductIngredient{}
|
||||
product := &entities.Product{}
|
||||
ingredient := &entities.Ingredient{}
|
||||
|
||||
err := rows.Scan(
|
||||
&productIngredient.ID,
|
||||
&productIngredient.OrganizationID,
|
||||
&productIngredient.OutletID,
|
||||
&productIngredient.ProductID,
|
||||
&productIngredient.IngredientID,
|
||||
&productIngredient.Quantity,
|
||||
&productIngredient.CreatedAt,
|
||||
&productIngredient.UpdatedAt,
|
||||
&product.ID,
|
||||
&product.OrganizationID,
|
||||
&product.CategoryID,
|
||||
&product.SKU,
|
||||
&product.Name,
|
||||
&product.Description,
|
||||
&product.Price,
|
||||
&product.Cost,
|
||||
&product.BusinessType,
|
||||
&product.ImageURL,
|
||||
&product.PrinterType,
|
||||
&product.UnitID,
|
||||
&product.HasIngredients,
|
||||
&product.Metadata,
|
||||
&product.IsActive,
|
||||
&product.CreatedAt,
|
||||
&product.UpdatedAt,
|
||||
&ingredient.ID,
|
||||
&ingredient.OrganizationID,
|
||||
&ingredient.OutletID,
|
||||
&ingredient.Name,
|
||||
&ingredient.UnitID,
|
||||
&ingredient.Cost,
|
||||
&ingredient.Stock,
|
||||
&ingredient.IsSemiFinished,
|
||||
&ingredient.IsActive,
|
||||
&ingredient.Metadata,
|
||||
&ingredient.CreatedAt,
|
||||
&ingredient.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
productIngredient.Product = product
|
||||
productIngredient.Ingredient = ingredient
|
||||
productIngredients = append(productIngredients, productIngredient)
|
||||
}
|
||||
|
||||
return productIngredients, nil
|
||||
}
|
||||
|
||||
func (r *ProductIngredientRepository) GetByIngredientID(ctx context.Context, ingredientID, organizationID uuid.UUID) ([]*entities.ProductIngredient, error) {
|
||||
query := `
|
||||
SELECT pi.id, pi.organization_id, pi.outlet_id, pi.product_id, pi.ingredient_id, pi.quantity, pi.created_at, pi.updated_at,
|
||||
p.id, p.organization_id, p.category_id, p.sku, p.name, p.description, p.price, p.cost, p.business_type, p.image_url, p.printer_type, p.unit_id, p.has_ingredients, p.metadata, p.is_active, p.created_at, p.updated_at,
|
||||
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
|
||||
FROM product_ingredients pi
|
||||
LEFT JOIN products p ON pi.product_id = p.id
|
||||
LEFT JOIN ingredients i ON pi.ingredient_id = i.id
|
||||
WHERE pi.ingredient_id = $1 AND pi.organization_id = $2
|
||||
ORDER BY pi.created_at DESC
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(ctx, query, ingredientID, organizationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var productIngredients []*entities.ProductIngredient
|
||||
for rows.Next() {
|
||||
productIngredient := &entities.ProductIngredient{}
|
||||
product := &entities.Product{}
|
||||
ingredient := &entities.Ingredient{}
|
||||
|
||||
err := rows.Scan(
|
||||
&productIngredient.ID,
|
||||
&productIngredient.OrganizationID,
|
||||
&productIngredient.OutletID,
|
||||
&productIngredient.ProductID,
|
||||
&productIngredient.IngredientID,
|
||||
&productIngredient.Quantity,
|
||||
&productIngredient.CreatedAt,
|
||||
&productIngredient.UpdatedAt,
|
||||
&product.ID,
|
||||
&product.OrganizationID,
|
||||
&product.CategoryID,
|
||||
&product.SKU,
|
||||
&product.Name,
|
||||
&product.Description,
|
||||
&product.Price,
|
||||
&product.Cost,
|
||||
&product.BusinessType,
|
||||
&product.ImageURL,
|
||||
&product.PrinterType,
|
||||
&product.UnitID,
|
||||
&product.HasIngredients,
|
||||
&product.Metadata,
|
||||
&product.IsActive,
|
||||
&product.CreatedAt,
|
||||
&product.UpdatedAt,
|
||||
&ingredient.ID,
|
||||
&ingredient.OrganizationID,
|
||||
&ingredient.OutletID,
|
||||
&ingredient.Name,
|
||||
&ingredient.UnitID,
|
||||
&ingredient.Cost,
|
||||
&ingredient.Stock,
|
||||
&ingredient.IsSemiFinished,
|
||||
&ingredient.IsActive,
|
||||
&ingredient.Metadata,
|
||||
&ingredient.CreatedAt,
|
||||
&ingredient.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
productIngredient.Product = product
|
||||
productIngredient.Ingredient = ingredient
|
||||
productIngredients = append(productIngredients, productIngredient)
|
||||
}
|
||||
|
||||
return productIngredients, nil
|
||||
}
|
||||
|
||||
func (r *ProductIngredientRepository) Update(ctx context.Context, productIngredient *entities.ProductIngredient) error {
|
||||
query := `
|
||||
UPDATE product_ingredients
|
||||
SET outlet_id = $1, quantity = $2, updated_at = $3
|
||||
WHERE id = $4 AND organization_id = $5
|
||||
`
|
||||
|
||||
result, err := r.db.ExecContext(ctx, query,
|
||||
productIngredient.OutletID,
|
||||
productIngredient.Quantity,
|
||||
productIngredient.UpdatedAt,
|
||||
productIngredient.ID,
|
||||
productIngredient.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 *ProductIngredientRepository) Delete(ctx context.Context, id, organizationID uuid.UUID) error {
|
||||
query := `DELETE FROM product_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
|
||||
}
|
||||
|
||||
func (r *ProductIngredientRepository) DeleteByProductID(ctx context.Context, productID, organizationID uuid.UUID) error {
|
||||
query := `DELETE FROM product_ingredients WHERE product_id = $1 AND organization_id = $2`
|
||||
|
||||
_, err := r.db.ExecContext(ctx, query, productID, organizationID)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type UnitRepository struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewUnitRepository(db *sql.DB) *UnitRepository {
|
||||
return &UnitRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *UnitRepository) Create(ctx context.Context, unit *entities.Unit) error {
|
||||
query := `
|
||||
INSERT INTO units (id, organization_id, outlet_id, name, abbreviation, is_active, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
`
|
||||
|
||||
_, err := r.db.ExecContext(ctx, query,
|
||||
unit.ID,
|
||||
unit.OrganizationID,
|
||||
unit.OutletID,
|
||||
unit.Name,
|
||||
unit.Abbreviation,
|
||||
unit.IsActive,
|
||||
unit.CreatedAt,
|
||||
unit.UpdatedAt,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *UnitRepository) GetByID(ctx context.Context, id, organizationID uuid.UUID) (*entities.Unit, error) {
|
||||
query := `
|
||||
SELECT id, organization_id, outlet_id, name, abbreviation, is_active, created_at, updated_at
|
||||
FROM units
|
||||
WHERE id = $1 AND organization_id = $2
|
||||
`
|
||||
|
||||
unit := &entities.Unit{}
|
||||
err := r.db.QueryRowContext(ctx, query, id, organizationID).Scan(
|
||||
&unit.ID,
|
||||
&unit.OrganizationID,
|
||||
&unit.OutletID,
|
||||
&unit.Name,
|
||||
&unit.Abbreviation,
|
||||
&unit.IsActive,
|
||||
&unit.CreatedAt,
|
||||
&unit.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unit, nil
|
||||
}
|
||||
|
||||
func (r *UnitRepository) GetAll(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, page, limit int, search string) ([]*entities.Unit, int, error) {
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// Build WHERE clause
|
||||
whereClause := "WHERE organization_id = $1"
|
||||
args := []interface{}{organizationID}
|
||||
argCount := 1
|
||||
|
||||
if outletID != nil {
|
||||
argCount++
|
||||
whereClause += fmt.Sprintf(" AND outlet_id = $%d", argCount)
|
||||
args = append(args, *outletID)
|
||||
}
|
||||
|
||||
if search != "" {
|
||||
argCount++
|
||||
whereClause += fmt.Sprintf(" AND (name ILIKE $%d OR abbreviation ILIKE $%d)", argCount, argCount)
|
||||
args = append(args, "%"+search+"%")
|
||||
}
|
||||
|
||||
// Count query
|
||||
countQuery := fmt.Sprintf("SELECT COUNT(*) FROM units %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 id, organization_id, outlet_id, name, abbreviation, is_active, created_at, updated_at
|
||||
FROM units
|
||||
%s
|
||||
ORDER BY 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 units []*entities.Unit
|
||||
for rows.Next() {
|
||||
unit := &entities.Unit{}
|
||||
err := rows.Scan(
|
||||
&unit.ID,
|
||||
&unit.OrganizationID,
|
||||
&unit.OutletID,
|
||||
&unit.Name,
|
||||
&unit.Abbreviation,
|
||||
&unit.IsActive,
|
||||
&unit.CreatedAt,
|
||||
&unit.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
units = append(units, unit)
|
||||
}
|
||||
|
||||
return units, total, nil
|
||||
}
|
||||
|
||||
func (r *UnitRepository) Update(ctx context.Context, unit *entities.Unit) error {
|
||||
query := `
|
||||
UPDATE units
|
||||
SET outlet_id = $1, name = $2, abbreviation = $3, is_active = $4, updated_at = $5
|
||||
WHERE id = $6 AND organization_id = $7
|
||||
`
|
||||
|
||||
result, err := r.db.ExecContext(ctx, query,
|
||||
unit.OutletID,
|
||||
unit.Name,
|
||||
unit.Abbreviation,
|
||||
unit.IsActive,
|
||||
unit.UpdatedAt,
|
||||
unit.ID,
|
||||
unit.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 *UnitRepository) Delete(ctx context.Context, id, organizationID uuid.UUID) error {
|
||||
query := `DELETE FROM units 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
|
||||
}
|
||||
Reference in New Issue
Block a user