package repository import ( "context" "strings" "time" "github.com/google/uuid" "apskel-pos-be/internal/entities" "gorm.io/gorm" ) type PurchaseOrderRepositoryImpl struct { db *gorm.DB } func NewPurchaseOrderRepositoryImpl(db *gorm.DB) *PurchaseOrderRepositoryImpl { return &PurchaseOrderRepositoryImpl{ db: db, } } func (r *PurchaseOrderRepositoryImpl) Create(ctx context.Context, po *entities.PurchaseOrder) error { return r.db.WithContext(ctx).Create(po).Error } func (r *PurchaseOrderRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.PurchaseOrder, error) { var po entities.PurchaseOrder err := r.db.WithContext(ctx). Preload("Vendor"). Preload("Items.Ingredient"). Preload("Items.Unit"). Preload("Attachments.File"). First(&po, "id = ?", id).Error if err != nil { return nil, err } return &po, nil } func (r *PurchaseOrderRepositoryImpl) GetByIDAndOrganizationID(ctx context.Context, id, organizationID uuid.UUID) (*entities.PurchaseOrder, error) { var po entities.PurchaseOrder err := r.db.WithContext(ctx). Preload("Vendor"). Preload("Items.Ingredient"). Preload("Items.Unit"). Preload("Attachments.File"). Where("id = ? AND organization_id = ?", id, organizationID). First(&po).Error if err != nil { return nil, err } return &po, nil } func (r *PurchaseOrderRepositoryImpl) Update(ctx context.Context, po *entities.PurchaseOrder) error { return r.db.WithContext(ctx).Save(po).Error } func (r *PurchaseOrderRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error { return r.db.WithContext(ctx).Delete(&entities.PurchaseOrder{}, "id = ?", id).Error } func (r *PurchaseOrderRepositoryImpl) List(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, limit, offset int) ([]*entities.PurchaseOrder, int64, error) { var pos []*entities.PurchaseOrder var total int64 query := r.db.WithContext(ctx).Model(&entities.PurchaseOrder{}).Where("organization_id = ?", organizationID) // Apply filters for key, value := range filters { switch key { case "search": if searchStr, ok := value.(string); ok && searchStr != "" { searchPattern := "%" + strings.ToLower(searchStr) + "%" query = query.Where("LOWER(po_number) LIKE ? OR LOWER(reference) LIKE ?", searchPattern, searchPattern) } case "status": if status, ok := value.(string); ok && status != "" { query = query.Where("status = ?", status) } case "vendor_id": if vendorID, ok := value.(uuid.UUID); ok { query = query.Where("vendor_id = ?", vendorID) } 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("Vendor"). Preload("Items.Ingredient"). Preload("Items.Unit"). Preload("Attachments.File"). Order("created_at DESC"). Limit(limit). Offset(offset). Find(&pos).Error return pos, total, err } func (r *PurchaseOrderRepositoryImpl) Count(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}) (int64, error) { var count int64 query := r.db.WithContext(ctx).Model(&entities.PurchaseOrder{}).Where("organization_id = ?", organizationID) // Apply filters for key, value := range filters { switch key { case "search": if searchStr, ok := value.(string); ok && searchStr != "" { searchPattern := "%" + strings.ToLower(searchStr) + "%" query = query.Where("LOWER(po_number) LIKE ? OR LOWER(reference) LIKE ?", searchPattern, searchPattern) } case "status": if status, ok := value.(string); ok && status != "" { query = query.Where("status = ?", status) } case "vendor_id": if vendorID, ok := value.(uuid.UUID); ok { query = query.Where("vendor_id = ?", vendorID) } 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) } } err := query.Count(&count).Error return count, err } func (r *PurchaseOrderRepositoryImpl) GetByPONumber(ctx context.Context, poNumber string, organizationID uuid.UUID) (*entities.PurchaseOrder, error) { var po entities.PurchaseOrder err := r.db.WithContext(ctx). Where("po_number = ? AND organization_id = ?", poNumber, organizationID). First(&po).Error if err != nil { return nil, err } return &po, nil } func (r *PurchaseOrderRepositoryImpl) GetByStatus(ctx context.Context, organizationID uuid.UUID, status string) ([]*entities.PurchaseOrder, error) { var pos []*entities.PurchaseOrder err := r.db.WithContext(ctx). Where("organization_id = ? AND status = ?", organizationID, status). Preload("Vendor"). Preload("Items.Ingredient"). Preload("Items.Unit"). Find(&pos).Error return pos, err } func (r *PurchaseOrderRepositoryImpl) GetOverdue(ctx context.Context, organizationID uuid.UUID) ([]*entities.PurchaseOrder, error) { var pos []*entities.PurchaseOrder err := r.db.WithContext(ctx). Where("organization_id = ? AND due_date < ? AND status IN (?)", organizationID, time.Now(), []string{"draft", "sent", "approved"}). Preload("Vendor"). Preload("Items.Ingredient"). Preload("Items.Unit"). Find(&pos).Error return pos, err } func (r *PurchaseOrderRepositoryImpl) UpdateStatus(ctx context.Context, id uuid.UUID, status string) error { return r.db.WithContext(ctx). Model(&entities.PurchaseOrder{}). Where("id = ?", id). Update("status", status).Error } func (r *PurchaseOrderRepositoryImpl) UpdateTotalAmount(ctx context.Context, id uuid.UUID, totalAmount float64) error { return r.db.WithContext(ctx). Model(&entities.PurchaseOrder{}). Where("id = ?", id). Update("total_amount", totalAmount).Error } // Purchase Order Items methods func (r *PurchaseOrderRepositoryImpl) CreateItem(ctx context.Context, item *entities.PurchaseOrderItem) error { return r.db.WithContext(ctx).Create(item).Error } func (r *PurchaseOrderRepositoryImpl) UpdateItem(ctx context.Context, item *entities.PurchaseOrderItem) error { return r.db.WithContext(ctx).Save(item).Error } func (r *PurchaseOrderRepositoryImpl) DeleteItem(ctx context.Context, id uuid.UUID) error { return r.db.WithContext(ctx).Delete(&entities.PurchaseOrderItem{}, "id = ?", id).Error } func (r *PurchaseOrderRepositoryImpl) DeleteItemsByPurchaseOrderID(ctx context.Context, purchaseOrderID uuid.UUID) error { return r.db.WithContext(ctx).Delete(&entities.PurchaseOrderItem{}, "purchase_order_id = ?", purchaseOrderID).Error } func (r *PurchaseOrderRepositoryImpl) GetItemsByPurchaseOrderID(ctx context.Context, purchaseOrderID uuid.UUID) ([]*entities.PurchaseOrderItem, error) { var items []*entities.PurchaseOrderItem err := r.db.WithContext(ctx). Preload("Ingredient"). Preload("Unit"). Where("purchase_order_id = ?", purchaseOrderID). Find(&items).Error return items, err } // Purchase Order Attachments methods func (r *PurchaseOrderRepositoryImpl) CreateAttachment(ctx context.Context, attachment *entities.PurchaseOrderAttachment) error { return r.db.WithContext(ctx).Create(attachment).Error } func (r *PurchaseOrderRepositoryImpl) DeleteAttachment(ctx context.Context, id uuid.UUID) error { return r.db.WithContext(ctx).Delete(&entities.PurchaseOrderAttachment{}, "id = ?", id).Error } func (r *PurchaseOrderRepositoryImpl) DeleteAttachmentsByPurchaseOrderID(ctx context.Context, purchaseOrderID uuid.UUID) error { return r.db.WithContext(ctx).Delete(&entities.PurchaseOrderAttachment{}, "purchase_order_id = ?", purchaseOrderID).Error } func (r *PurchaseOrderRepositoryImpl) GetAttachmentsByPurchaseOrderID(ctx context.Context, purchaseOrderID uuid.UUID) ([]*entities.PurchaseOrderAttachment, error) { var attachments []*entities.PurchaseOrderAttachment err := r.db.WithContext(ctx). Preload("File"). Where("purchase_order_id = ?", purchaseOrderID). Find(&attachments).Error return attachments, err }