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 }