Add coa purchase and vendors

This commit is contained in:
Aditya Siregar
2025-09-12 01:12:11 +07:00
parent c107733add
commit efe09c21e4
86 changed files with 8517 additions and 212 deletions
+147
View File
@@ -0,0 +1,147 @@
package repository
import (
"context"
"github.com/google/uuid"
"apskel-pos-be/internal/entities"
"gorm.io/gorm"
)
type AccountRepository interface {
Create(ctx context.Context, account *entities.Account) error
GetByID(ctx context.Context, id uuid.UUID) (*entities.Account, error)
Update(ctx context.Context, account *entities.Account) error
Delete(ctx context.Context, id uuid.UUID) error
List(ctx context.Context, req *entities.Account) ([]*entities.Account, int, error)
GetByOrganization(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]*entities.Account, error)
GetByChartOfAccount(ctx context.Context, chartOfAccountID uuid.UUID) ([]*entities.Account, error)
GetByNumber(ctx context.Context, organizationID uuid.UUID, number string, outletID *uuid.UUID) (*entities.Account, error)
UpdateBalance(ctx context.Context, id uuid.UUID, amount float64) error
GetBalance(ctx context.Context, id uuid.UUID) (float64, error)
GetSystemAccounts(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]*entities.Account, error)
}
type AccountRepositoryImpl struct {
db *gorm.DB
}
func NewAccountRepositoryImpl(db *gorm.DB) *AccountRepositoryImpl {
return &AccountRepositoryImpl{
db: db,
}
}
func (r *AccountRepositoryImpl) Create(ctx context.Context, account *entities.Account) error {
return r.db.WithContext(ctx).Create(account).Error
}
func (r *AccountRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.Account, error) {
var account entities.Account
err := r.db.WithContext(ctx).Preload("ChartOfAccount").Preload("ChartOfAccount.ChartOfAccountType").First(&account, "id = ?", id).Error
if err != nil {
return nil, err
}
return &account, nil
}
func (r *AccountRepositoryImpl) Update(ctx context.Context, account *entities.Account) error {
return r.db.WithContext(ctx).Save(account).Error
}
func (r *AccountRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error {
return r.db.WithContext(ctx).Delete(&entities.Account{}, "id = ?", id).Error
}
func (r *AccountRepositoryImpl) List(ctx context.Context, req *entities.Account) ([]*entities.Account, int, error) {
var accounts []*entities.Account
var total int64
query := r.db.WithContext(ctx).Model(&entities.Account{})
// Apply filters
if req.OrganizationID != uuid.Nil {
query = query.Where("organization_id = ?", req.OrganizationID)
}
if req.OutletID != nil {
query = query.Where("outlet_id = ?", *req.OutletID)
}
if req.ChartOfAccountID != uuid.Nil {
query = query.Where("chart_of_account_id = ?", req.ChartOfAccountID)
}
if req.AccountType != "" {
query = query.Where("account_type = ?", req.AccountType)
}
// Count total
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// Apply pagination and preloads
err := query.Preload("ChartOfAccount").Preload("ChartOfAccount.ChartOfAccountType").Find(&accounts).Error
return accounts, int(total), err
}
func (r *AccountRepositoryImpl) GetByOrganization(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]*entities.Account, error) {
var accounts []*entities.Account
query := r.db.WithContext(ctx).Where("organization_id = ?", organizationID)
if outletID != nil {
query = query.Where("outlet_id = ?", *outletID)
} else {
query = query.Where("outlet_id IS NULL")
}
err := query.Preload("ChartOfAccount").Preload("ChartOfAccount.ChartOfAccountType").Find(&accounts).Error
return accounts, err
}
func (r *AccountRepositoryImpl) GetByChartOfAccount(ctx context.Context, chartOfAccountID uuid.UUID) ([]*entities.Account, error) {
var accounts []*entities.Account
err := r.db.WithContext(ctx).Where("chart_of_account_id = ?", chartOfAccountID).Preload("ChartOfAccount").Preload("ChartOfAccount.ChartOfAccountType").Find(&accounts).Error
return accounts, err
}
func (r *AccountRepositoryImpl) GetByNumber(ctx context.Context, organizationID uuid.UUID, number string, outletID *uuid.UUID) (*entities.Account, error) {
var account entities.Account
query := r.db.WithContext(ctx).Where("organization_id = ? AND number = ?", organizationID, number)
if outletID != nil {
query = query.Where("outlet_id = ?", *outletID)
} else {
query = query.Where("outlet_id IS NULL")
}
err := query.Preload("ChartOfAccount").Preload("ChartOfAccount.ChartOfAccountType").First(&account).Error
if err != nil {
return nil, err
}
return &account, nil
}
func (r *AccountRepositoryImpl) UpdateBalance(ctx context.Context, id uuid.UUID, amount float64) error {
return r.db.WithContext(ctx).Model(&entities.Account{}).Where("id = ?", id).Update("current_balance", amount).Error
}
func (r *AccountRepositoryImpl) GetBalance(ctx context.Context, id uuid.UUID) (float64, error) {
var balance float64
err := r.db.WithContext(ctx).Model(&entities.Account{}).Select("current_balance").Where("id = ?", id).Scan(&balance).Error
return balance, err
}
func (r *AccountRepositoryImpl) GetSystemAccounts(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]*entities.Account, error) {
var accounts []*entities.Account
query := r.db.WithContext(ctx).Where("organization_id = ? AND is_system = ?", organizationID, true)
if outletID != nil {
query = query.Where("outlet_id = ?", *outletID)
} else {
query = query.Where("outlet_id IS NULL")
}
err := query.Preload("ChartOfAccount").Preload("ChartOfAccount.ChartOfAccountType").Find(&accounts).Error
return accounts, err
}
@@ -0,0 +1,143 @@
package repository
import (
"context"
"github.com/google/uuid"
"apskel-pos-be/internal/entities"
"gorm.io/gorm"
)
type ChartOfAccountRepository interface {
Create(ctx context.Context, chartOfAccount *entities.ChartOfAccount) error
GetByID(ctx context.Context, id uuid.UUID) (*entities.ChartOfAccount, error)
Update(ctx context.Context, chartOfAccount *entities.ChartOfAccount) error
Delete(ctx context.Context, id uuid.UUID) error
List(ctx context.Context, req *entities.ChartOfAccount) ([]*entities.ChartOfAccount, int, error)
GetByOrganization(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]*entities.ChartOfAccount, error)
GetByType(ctx context.Context, organizationID uuid.UUID, chartOfAccountTypeID uuid.UUID, outletID *uuid.UUID) ([]*entities.ChartOfAccount, error)
GetByCode(ctx context.Context, organizationID uuid.UUID, code string, outletID *uuid.UUID) (*entities.ChartOfAccount, error)
GetSystemAccounts(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]*entities.ChartOfAccount, error)
}
type ChartOfAccountRepositoryImpl struct {
db *gorm.DB
}
func NewChartOfAccountRepositoryImpl(db *gorm.DB) *ChartOfAccountRepositoryImpl {
return &ChartOfAccountRepositoryImpl{
db: db,
}
}
func (r *ChartOfAccountRepositoryImpl) Create(ctx context.Context, chartOfAccount *entities.ChartOfAccount) error {
return r.db.WithContext(ctx).Create(chartOfAccount).Error
}
func (r *ChartOfAccountRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.ChartOfAccount, error) {
var chartOfAccount entities.ChartOfAccount
err := r.db.WithContext(ctx).Preload("ChartOfAccountType").Preload("Parent").Preload("Children").First(&chartOfAccount, "id = ?", id).Error
if err != nil {
return nil, err
}
return &chartOfAccount, nil
}
func (r *ChartOfAccountRepositoryImpl) Update(ctx context.Context, chartOfAccount *entities.ChartOfAccount) error {
return r.db.WithContext(ctx).Save(chartOfAccount).Error
}
func (r *ChartOfAccountRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error {
return r.db.WithContext(ctx).Delete(&entities.ChartOfAccount{}, "id = ?", id).Error
}
func (r *ChartOfAccountRepositoryImpl) List(ctx context.Context, req *entities.ChartOfAccount) ([]*entities.ChartOfAccount, int, error) {
var chartOfAccounts []*entities.ChartOfAccount
var total int64
query := r.db.WithContext(ctx).Model(&entities.ChartOfAccount{})
// Apply filters
if req.OrganizationID != uuid.Nil {
query = query.Where("organization_id = ?", req.OrganizationID)
}
if req.OutletID != nil {
query = query.Where("outlet_id = ?", *req.OutletID)
}
if req.ChartOfAccountTypeID != uuid.Nil {
query = query.Where("chart_of_account_type_id = ?", req.ChartOfAccountTypeID)
}
if req.ParentID != nil {
query = query.Where("parent_id = ?", *req.ParentID)
}
// Count total
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// Apply pagination and preloads
err := query.Preload("ChartOfAccountType").Preload("Parent").Preload("Children").Find(&chartOfAccounts).Error
return chartOfAccounts, int(total), err
}
func (r *ChartOfAccountRepositoryImpl) GetByOrganization(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]*entities.ChartOfAccount, error) {
var chartOfAccounts []*entities.ChartOfAccount
query := r.db.WithContext(ctx).Where("organization_id = ?", organizationID)
if outletID != nil {
query = query.Where("outlet_id = ?", *outletID)
} else {
query = query.Where("outlet_id IS NULL")
}
err := query.Preload("ChartOfAccountType").Preload("Parent").Preload("Children").Find(&chartOfAccounts).Error
return chartOfAccounts, err
}
func (r *ChartOfAccountRepositoryImpl) GetByType(ctx context.Context, organizationID uuid.UUID, chartOfAccountTypeID uuid.UUID, outletID *uuid.UUID) ([]*entities.ChartOfAccount, error) {
var chartOfAccounts []*entities.ChartOfAccount
query := r.db.WithContext(ctx).Where("organization_id = ? AND chart_of_account_type_id = ?", organizationID, chartOfAccountTypeID)
if outletID != nil {
query = query.Where("outlet_id = ?", *outletID)
} else {
query = query.Where("outlet_id IS NULL")
}
err := query.Preload("ChartOfAccountType").Preload("Parent").Preload("Children").Find(&chartOfAccounts).Error
return chartOfAccounts, err
}
func (r *ChartOfAccountRepositoryImpl) GetByCode(ctx context.Context, organizationID uuid.UUID, code string, outletID *uuid.UUID) (*entities.ChartOfAccount, error) {
var chartOfAccount entities.ChartOfAccount
query := r.db.WithContext(ctx).Where("organization_id = ? AND code = ?", organizationID, code)
if outletID != nil {
query = query.Where("outlet_id = ?", *outletID)
} else {
query = query.Where("outlet_id IS NULL")
}
err := query.Preload("ChartOfAccountType").Preload("Parent").First(&chartOfAccount).Error
if err != nil {
return nil, err
}
return &chartOfAccount, nil
}
func (r *ChartOfAccountRepositoryImpl) GetSystemAccounts(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]*entities.ChartOfAccount, error) {
var chartOfAccounts []*entities.ChartOfAccount
query := r.db.WithContext(ctx).Where("organization_id = ? AND is_system = ?", organizationID, true)
if outletID != nil {
query = query.Where("outlet_id = ?", *outletID)
} else {
query = query.Where("outlet_id IS NULL")
}
err := query.Preload("ChartOfAccountType").Preload("Parent").Find(&chartOfAccounts).Error
return chartOfAccounts, err
}
@@ -0,0 +1,91 @@
package repository
import (
"context"
"github.com/google/uuid"
"apskel-pos-be/internal/entities"
"gorm.io/gorm"
)
type ChartOfAccountTypeRepository interface {
Create(ctx context.Context, chartOfAccountType *entities.ChartOfAccountType) error
GetByID(ctx context.Context, id uuid.UUID) (*entities.ChartOfAccountType, error)
GetByCode(ctx context.Context, code string) (*entities.ChartOfAccountType, error)
Update(ctx context.Context, chartOfAccountType *entities.ChartOfAccountType) error
Delete(ctx context.Context, id uuid.UUID) error
List(ctx context.Context, filters map[string]interface{}, page, limit int) ([]*entities.ChartOfAccountType, int, error)
GetActive(ctx context.Context) ([]*entities.ChartOfAccountType, error)
}
type ChartOfAccountTypeRepositoryImpl struct {
db *gorm.DB
}
func NewChartOfAccountTypeRepositoryImpl(db *gorm.DB) *ChartOfAccountTypeRepositoryImpl {
return &ChartOfAccountTypeRepositoryImpl{
db: db,
}
}
func (r *ChartOfAccountTypeRepositoryImpl) Create(ctx context.Context, chartOfAccountType *entities.ChartOfAccountType) error {
return r.db.WithContext(ctx).Create(chartOfAccountType).Error
}
func (r *ChartOfAccountTypeRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.ChartOfAccountType, error) {
var chartOfAccountType entities.ChartOfAccountType
err := r.db.WithContext(ctx).First(&chartOfAccountType, "id = ?", id).Error
if err != nil {
return nil, err
}
return &chartOfAccountType, nil
}
func (r *ChartOfAccountTypeRepositoryImpl) GetByCode(ctx context.Context, code string) (*entities.ChartOfAccountType, error) {
var chartOfAccountType entities.ChartOfAccountType
err := r.db.WithContext(ctx).First(&chartOfAccountType, "code = ?", code).Error
if err != nil {
return nil, err
}
return &chartOfAccountType, nil
}
func (r *ChartOfAccountTypeRepositoryImpl) Update(ctx context.Context, chartOfAccountType *entities.ChartOfAccountType) error {
return r.db.WithContext(ctx).Save(chartOfAccountType).Error
}
func (r *ChartOfAccountTypeRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error {
return r.db.WithContext(ctx).Delete(&entities.ChartOfAccountType{}, "id = ?", id).Error
}
func (r *ChartOfAccountTypeRepositoryImpl) List(ctx context.Context, filters map[string]interface{}, page, limit int) ([]*entities.ChartOfAccountType, int, error) {
var chartOfAccountTypes []*entities.ChartOfAccountType
var total int64
query := r.db.WithContext(ctx).Model(&entities.ChartOfAccountType{})
// Apply filters
for key, value := range filters {
if value != nil {
query = query.Where(key+" = ?", value)
}
}
// Count total
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// Apply pagination
offset := (page - 1) * limit
err := query.Offset(offset).Limit(limit).Find(&chartOfAccountTypes).Error
return chartOfAccountTypes, int(total), err
}
func (r *ChartOfAccountTypeRepositoryImpl) GetActive(ctx context.Context) ([]*entities.ChartOfAccountType, error) {
var chartOfAccountTypes []*entities.ChartOfAccountType
err := r.db.WithContext(ctx).Where("is_active = ?", true).Find(&chartOfAccountTypes).Error
return chartOfAccountTypes, err
}
@@ -0,0 +1,176 @@
package repository
import (
"apskel-pos-be/internal/entities"
"context"
"fmt"
"github.com/google/uuid"
"gorm.io/gorm"
)
type IngredientUnitConverterRepository interface {
Create(ctx context.Context, converter *entities.IngredientUnitConverter) error
GetByID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error)
GetByIDAndOrganizationID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error)
Update(ctx context.Context, converter *entities.IngredientUnitConverter) error
Delete(ctx context.Context, id, organizationID uuid.UUID) error
List(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, page, limit int) ([]*entities.IngredientUnitConverter, int, error)
GetByIngredientAndUnits(ctx context.Context, ingredientID, fromUnitID, toUnitID, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error)
GetConvertersForIngredient(ctx context.Context, ingredientID, organizationID uuid.UUID) ([]*entities.IngredientUnitConverter, error)
GetActiveConverters(ctx context.Context, organizationID uuid.UUID) ([]*entities.IngredientUnitConverter, error)
ConvertQuantity(ctx context.Context, ingredientID, fromUnitID, toUnitID, organizationID uuid.UUID, quantity float64) (float64, error)
}
type IngredientUnitConverterRepositoryImpl struct {
db *gorm.DB
}
func NewIngredientUnitConverterRepositoryImpl(db *gorm.DB) IngredientUnitConverterRepository {
return &IngredientUnitConverterRepositoryImpl{
db: db,
}
}
func (r *IngredientUnitConverterRepositoryImpl) Create(ctx context.Context, converter *entities.IngredientUnitConverter) error {
return r.db.WithContext(ctx).Create(converter).Error
}
func (r *IngredientUnitConverterRepositoryImpl) GetByID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error) {
var converter entities.IngredientUnitConverter
err := r.db.WithContext(ctx).
Where("id = ? AND organization_id = ?", id, organizationID).
Preload("Ingredient").
Preload("FromUnit").
Preload("ToUnit").
Preload("CreatedByUser").
Preload("UpdatedByUser").
First(&converter).Error
if err != nil {
return nil, err
}
return &converter, nil
}
func (r *IngredientUnitConverterRepositoryImpl) GetByIDAndOrganizationID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error) {
return r.GetByID(ctx, id, organizationID)
}
func (r *IngredientUnitConverterRepositoryImpl) Update(ctx context.Context, converter *entities.IngredientUnitConverter) error {
return r.db.WithContext(ctx).Save(converter).Error
}
func (r *IngredientUnitConverterRepositoryImpl) Delete(ctx context.Context, id, organizationID uuid.UUID) error {
return r.db.WithContext(ctx).
Where("id = ? AND organization_id = ?", id, organizationID).
Delete(&entities.IngredientUnitConverter{}).Error
}
func (r *IngredientUnitConverterRepositoryImpl) List(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, page, limit int) ([]*entities.IngredientUnitConverter, int, error) {
var converters []*entities.IngredientUnitConverter
var total int64
query := r.db.WithContext(ctx).
Model(&entities.IngredientUnitConverter{}).
Where("organization_id = ?", organizationID)
// Apply filters
if ingredientID, ok := filters["ingredient_id"].(uuid.UUID); ok {
query = query.Where("ingredient_id = ?", ingredientID)
}
if fromUnitID, ok := filters["from_unit_id"].(uuid.UUID); ok {
query = query.Where("from_unit_id = ?", fromUnitID)
}
if toUnitID, ok := filters["to_unit_id"].(uuid.UUID); ok {
query = query.Where("to_unit_id = ?", toUnitID)
}
if isActive, ok := filters["is_active"].(bool); ok {
query = query.Where("is_active = ?", isActive)
}
if search, ok := filters["search"].(string); ok && search != "" {
query = query.Joins("LEFT JOIN ingredients ON ingredient_unit_converters.ingredient_id = ingredients.id").
Joins("LEFT JOIN units AS from_units ON ingredient_unit_converters.from_unit_id = from_units.id").
Joins("LEFT JOIN units AS to_units ON ingredient_unit_converters.to_unit_id = to_units.id").
Where("ingredients.name ILIKE ? OR from_units.name ILIKE ? OR to_units.name ILIKE ?",
"%"+search+"%", "%"+search+"%", "%"+search+"%")
}
// Get total count
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// Apply pagination and get results
offset := (page - 1) * limit
err := query.
Preload("Ingredient").
Preload("FromUnit").
Preload("ToUnit").
Preload("CreatedByUser").
Preload("UpdatedByUser").
Order("created_at DESC").
Offset(offset).
Limit(limit).
Find(&converters).Error
return converters, int(total), err
}
func (r *IngredientUnitConverterRepositoryImpl) GetByIngredientAndUnits(ctx context.Context, ingredientID, fromUnitID, toUnitID, organizationID uuid.UUID) (*entities.IngredientUnitConverter, error) {
var converter entities.IngredientUnitConverter
err := r.db.WithContext(ctx).
Where("ingredient_id = ? AND from_unit_id = ? AND to_unit_id = ? AND organization_id = ? AND is_active = ?",
ingredientID, fromUnitID, toUnitID, organizationID, true).
Preload("Ingredient").
Preload("FromUnit").
Preload("ToUnit").
First(&converter).Error
if err != nil {
return nil, err
}
return &converter, nil
}
func (r *IngredientUnitConverterRepositoryImpl) GetConvertersForIngredient(ctx context.Context, ingredientID, organizationID uuid.UUID) ([]*entities.IngredientUnitConverter, error) {
var converters []*entities.IngredientUnitConverter
err := r.db.WithContext(ctx).
Where("ingredient_id = ? AND organization_id = ? AND is_active = ?", ingredientID, organizationID, true).
Preload("FromUnit").
Preload("ToUnit").
Find(&converters).Error
return converters, err
}
func (r *IngredientUnitConverterRepositoryImpl) GetActiveConverters(ctx context.Context, organizationID uuid.UUID) ([]*entities.IngredientUnitConverter, error) {
var converters []*entities.IngredientUnitConverter
err := r.db.WithContext(ctx).
Where("organization_id = ? AND is_active = ?", organizationID, true).
Preload("Ingredient").
Preload("FromUnit").
Preload("ToUnit").
Find(&converters).Error
return converters, err
}
func (r *IngredientUnitConverterRepositoryImpl) ConvertQuantity(ctx context.Context, ingredientID, fromUnitID, toUnitID, organizationID uuid.UUID, quantity float64) (float64, error) {
// If from and to units are the same, return the same quantity
if fromUnitID == toUnitID {
return quantity, nil
}
// Try to find direct converter
converter, err := r.GetByIngredientAndUnits(ctx, ingredientID, fromUnitID, toUnitID, organizationID)
if err == nil {
return quantity * converter.ConversionFactor, nil
}
// If direct converter not found, try to find reverse converter
reverseConverter, err := r.GetByIngredientAndUnits(ctx, ingredientID, toUnitID, fromUnitID, organizationID)
if err == nil {
return quantity / reverseConverter.ConversionFactor, nil
}
// If no converter found, return error
return 0, fmt.Errorf("no conversion found between units %s and %s for ingredient %s", fromUnitID, toUnitID, ingredientID)
}
@@ -0,0 +1,248 @@
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
}
+134
View File
@@ -0,0 +1,134 @@
package repository
import (
"context"
"strings"
"github.com/google/uuid"
"apskel-pos-be/internal/entities"
"gorm.io/gorm"
)
type VendorRepositoryImpl struct {
db *gorm.DB
}
func NewVendorRepositoryImpl(db *gorm.DB) *VendorRepositoryImpl {
return &VendorRepositoryImpl{
db: db,
}
}
func (r *VendorRepositoryImpl) Create(ctx context.Context, vendor *entities.Vendor) error {
return r.db.WithContext(ctx).Create(vendor).Error
}
func (r *VendorRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.Vendor, error) {
var vendor entities.Vendor
err := r.db.WithContext(ctx).First(&vendor, "id = ?", id).Error
if err != nil {
return nil, err
}
return &vendor, nil
}
func (r *VendorRepositoryImpl) GetByIDAndOrganizationID(ctx context.Context, id, organizationID uuid.UUID) (*entities.Vendor, error) {
var vendor entities.Vendor
err := r.db.WithContext(ctx).Where("id = ? AND organization_id = ?", id, organizationID).First(&vendor).Error
if err != nil {
return nil, err
}
return &vendor, nil
}
func (r *VendorRepositoryImpl) Update(ctx context.Context, vendor *entities.Vendor) error {
return r.db.WithContext(ctx).Save(vendor).Error
}
func (r *VendorRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error {
return r.db.WithContext(ctx).Delete(&entities.Vendor{}, "id = ?", id).Error
}
func (r *VendorRepositoryImpl) List(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, limit, offset int) ([]*entities.Vendor, int64, error) {
var vendors []*entities.Vendor
var total int64
query := r.db.WithContext(ctx).Model(&entities.Vendor{}).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(name) LIKE ? OR LOWER(email) LIKE ? OR LOWER(contact_person) LIKE ?",
searchPattern, searchPattern, searchPattern)
}
case "is_active":
if isActive, ok := value.(bool); ok {
query = query.Where("is_active = ?", isActive)
}
default:
query = query.Where(key+" = ?", value)
}
}
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
err := query.Order("created_at DESC").Limit(limit).Offset(offset).Find(&vendors).Error
return vendors, total, err
}
func (r *VendorRepositoryImpl) Count(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&entities.Vendor{}).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(name) LIKE ? OR LOWER(email) LIKE ? OR LOWER(contact_person) LIKE ?",
searchPattern, searchPattern, searchPattern)
}
case "is_active":
if isActive, ok := value.(bool); ok {
query = query.Where("is_active = ?", isActive)
}
default:
query = query.Where(key+" = ?", value)
}
}
err := query.Count(&count).Error
return count, err
}
func (r *VendorRepositoryImpl) GetByEmail(ctx context.Context, email string, organizationID uuid.UUID) (*entities.Vendor, error) {
var vendor entities.Vendor
err := r.db.WithContext(ctx).Where("email = ? AND organization_id = ?", email, organizationID).First(&vendor).Error
if err != nil {
return nil, err
}
return &vendor, nil
}
func (r *VendorRepositoryImpl) GetByName(ctx context.Context, name string, organizationID uuid.UUID) (*entities.Vendor, error) {
var vendor entities.Vendor
err := r.db.WithContext(ctx).Where("name = ? AND organization_id = ?", name, organizationID).First(&vendor).Error
if err != nil {
return nil, err
}
return &vendor, nil
}
func (r *VendorRepositoryImpl) GetActiveVendors(ctx context.Context, organizationID uuid.UUID) ([]*entities.Vendor, error) {
var vendors []*entities.Vendor
err := r.db.WithContext(ctx).Where("organization_id = ? AND is_active = ?", organizationID, true).Find(&vendors).Error
return vendors, err
}