- Implement local-first architecture with SQLite - Add bidirectional sync with Django via ChangeLog - JWT authentication with auto-refresh token - REST API for products, orders, commands, payments - Stock management with automatic deduction
411 lines
11 KiB
Go
411 lines
11 KiB
Go
package repository
|
|
|
|
import (
|
|
"fmt"
|
|
"gorm.io/gorm"
|
|
"log"
|
|
"rrbec_server/internal/models"
|
|
)
|
|
|
|
type Repository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewRepository(db *gorm.DB) *Repository {
|
|
return &Repository{db: db}
|
|
}
|
|
|
|
// Mesa
|
|
func (r *Repository) GetMesas() ([]models.Mesa, error) {
|
|
var mesas []models.Mesa
|
|
err := r.db.Find(&mesas).Error
|
|
return mesas, err
|
|
}
|
|
|
|
func (r *Repository) CreateMesa(mesa *models.Mesa) error {
|
|
return r.db.Create(mesa).Error
|
|
}
|
|
|
|
func (r *Repository) SaveMesa(mesa *models.Mesa) error {
|
|
return r.db.Save(mesa).Error
|
|
}
|
|
|
|
// Client
|
|
func (r *Repository) GetClients() ([]models.Client, error) {
|
|
var clients []models.Client
|
|
err := r.db.Find(&clients).Error
|
|
return clients, err
|
|
}
|
|
|
|
func (r *Repository) CreateClient(client *models.Client) error {
|
|
return r.db.Create(client).Error
|
|
}
|
|
|
|
func (r *Repository) SaveClient(client *models.Client) error {
|
|
return r.db.Save(client).Error
|
|
}
|
|
|
|
// Product
|
|
func (r *Repository) GetProducts() ([]models.Product, error) {
|
|
var products []models.Product
|
|
err := r.db.Find(&products).Error
|
|
return products, err
|
|
}
|
|
|
|
func (r *Repository) SaveProduct(product *models.Product) error {
|
|
return r.db.Save(product).Error
|
|
}
|
|
|
|
func (r *Repository) GetProductByID(id uint) (*models.Product, error) {
|
|
var product models.Product
|
|
err := r.db.First(&product, id).Error
|
|
return &product, err
|
|
}
|
|
|
|
func (r *Repository) UpdateProductFields(id uint, updates map[string]interface{}) error {
|
|
updates["sincronizado"] = false
|
|
return r.db.Model(&models.Product{}).Where("id = ?", id).Updates(updates).Error
|
|
}
|
|
|
|
func (r *Repository) DeductStock(productID uint, quantity int) error {
|
|
return r.db.Model(&models.Product{}).Where("id = ?", productID).
|
|
Update("quantity", gorm.Expr("quantity - ?", quantity)).Error
|
|
}
|
|
|
|
func (r *Repository) RestoreStock(productID uint, quantity int) error {
|
|
return r.db.Model(&models.Product{}).Where("id = ?", productID).
|
|
Update("quantity", gorm.Expr("quantity + ?", quantity)).Error
|
|
}
|
|
|
|
func (r *Repository) GetProductComponents(productID uint) ([]models.ProductComponent, error) {
|
|
var components []models.ProductComponent
|
|
err := r.db.Where("composite_product = ?", productID).Find(&components).Error
|
|
return components, err
|
|
}
|
|
|
|
func (r *Repository) CreateProduct(product *models.Product) error {
|
|
return r.db.Create(product).Error
|
|
}
|
|
|
|
// Comanda
|
|
func (r *Repository) GetComandas() ([]models.Comanda, error) {
|
|
var comandas []models.Comanda
|
|
if err := r.db.Find(&comandas).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// For each comanda, load its items
|
|
for i := range comandas {
|
|
var items []models.ProductComanda
|
|
r.db.Where("comanda_id = ?", comandas[i].ID).Find(&items)
|
|
comandas[i].Items = items
|
|
}
|
|
|
|
return comandas, nil
|
|
}
|
|
|
|
func (r *Repository) CreateComanda(comanda *models.Comanda) error {
|
|
return r.db.Create(comanda).Error
|
|
}
|
|
|
|
func (r *Repository) SaveComanda(comanda *models.Comanda) error {
|
|
return r.db.Save(comanda).Error
|
|
}
|
|
|
|
func (r *Repository) SaveCategory(cat *models.Category) error {
|
|
return r.db.Save(cat).Error
|
|
}
|
|
|
|
func (r *Repository) CreateCategory(cat *models.Category) error {
|
|
return r.db.Create(cat).Error
|
|
}
|
|
|
|
func (r *Repository) UpdateCategoryFields(id uint, updates map[string]interface{}) error {
|
|
return r.db.Model(&models.Category{}).Where("id = ?", id).Updates(updates).Error
|
|
}
|
|
|
|
func (r *Repository) SaveTypePay(tp *models.TypePay) error {
|
|
return r.db.Save(tp).Error
|
|
}
|
|
|
|
func (r *Repository) GetCategories() ([]models.Category, error) {
|
|
var categories []models.Category
|
|
err := r.db.Find(&categories).Error
|
|
return categories, err
|
|
}
|
|
|
|
func (r *Repository) GetTypePayments() ([]models.TypePay, error) {
|
|
var types []models.TypePay
|
|
err := r.db.Find(&types).Error
|
|
return types, err
|
|
}
|
|
|
|
func (r *Repository) GetComandaByID(id uint) (*models.Comanda, error) {
|
|
var comanda models.Comanda
|
|
if err := r.db.First(&comanda, id).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var items []models.ProductComanda
|
|
r.db.Where("comanda_id = ?", comanda.ID).Find(&items)
|
|
comanda.Items = items
|
|
|
|
return &comanda, nil
|
|
}
|
|
|
|
// Items
|
|
func (r *Repository) AddItemToComanda(item *models.ProductComanda) error {
|
|
return r.db.Create(item).Error
|
|
}
|
|
|
|
func (r *Repository) SaveProductComanda(item *models.ProductComanda) error {
|
|
return r.db.Save(item).Error
|
|
}
|
|
|
|
func (r *Repository) GetItemsByComanda(comandaID uint) ([]models.ProductComanda, error) {
|
|
var items []models.ProductComanda
|
|
err := r.db.Where("comanda_id = ?", comandaID).Find(&items).Error
|
|
return items, err
|
|
}
|
|
|
|
func (r *Repository) DeleteItem(itemID uint) error {
|
|
return r.db.Delete(&models.ProductComanda{}, itemID).Error
|
|
}
|
|
|
|
func (r *Repository) GetOrders() ([]models.Order, error) {
|
|
var orders []models.Order
|
|
err := r.db.Find(&orders).Error
|
|
return orders, err
|
|
}
|
|
|
|
func (r *Repository) SaveOrder(order *models.Order) error {
|
|
return r.db.Save(order).Error
|
|
}
|
|
|
|
func (r *Repository) CreateOrder(order *models.Order) error {
|
|
return r.db.Create(order).Error
|
|
}
|
|
|
|
func (r *Repository) GetOrderByPC(pcID uint) (*models.Order, error) {
|
|
var order models.Order
|
|
err := r.db.Where("product_comanda_id = ?", pcID).First(&order).Error
|
|
return &order, err
|
|
}
|
|
|
|
func (r *Repository) UpdateOrder(order *models.Order) error {
|
|
return r.db.Save(order).Error
|
|
}
|
|
|
|
func (r *Repository) UpdateOrderFields(id uint, updates map[string]interface{}) error {
|
|
mappedUpdates := make(map[string]interface{})
|
|
for k, v := range updates {
|
|
switch k {
|
|
case "productComanda":
|
|
mappedUpdates["product_comanda_id"] = v
|
|
case "id_product":
|
|
mappedUpdates["product_id"] = v
|
|
case "id_comanda":
|
|
mappedUpdates["comanda_id"] = v
|
|
default:
|
|
mappedUpdates[k] = v
|
|
}
|
|
}
|
|
|
|
mappedUpdates["sincronizado"] = false
|
|
|
|
return r.db.Model(&models.Order{}).Where("id = ?", id).Updates(mappedUpdates).Error
|
|
}
|
|
|
|
func (r *Repository) GetPayments() ([]models.Payment, error) {
|
|
var payments []models.Payment
|
|
err := r.db.Find(&payments).Error
|
|
return payments, err
|
|
}
|
|
|
|
func (r *Repository) CreatePayment(payment *models.Payment) error {
|
|
return r.db.Create(payment).Error
|
|
}
|
|
|
|
func (r *Repository) SavePayment(payment *models.Payment) error {
|
|
return r.db.Save(payment).Error
|
|
}
|
|
|
|
// Sync
|
|
func (r *Repository) GetUnsynced() (map[string][]interface{}, error) {
|
|
// This is a simplified helper to find anything not synced.
|
|
// In a real app, you'd iterate per table.
|
|
return nil, nil // Placeholder for sync worker logic
|
|
}
|
|
|
|
func (r *Repository) MarkAsSynced(model interface{}, id uint) error {
|
|
return r.db.Model(model).Where("id = ?", id).Update("sincronizado", true).Error
|
|
}
|
|
|
|
func (r *Repository) SafeChangeID(tableName string, oldID, newID uint) error {
|
|
if oldID == newID {
|
|
return nil
|
|
}
|
|
|
|
var count int64
|
|
r.db.Table(tableName).Where("id = ?", newID).Count(&count)
|
|
if count > 0 {
|
|
squatterID := newID + 1000000
|
|
for {
|
|
var sCount int64
|
|
r.db.Table(tableName).Where("id = ?", squatterID).Count(&sCount)
|
|
if sCount == 0 {
|
|
break
|
|
}
|
|
squatterID++
|
|
}
|
|
|
|
log.Printf("COLLISION: ID %d in %s taken! Moving squatter to %d", newID, tableName, squatterID)
|
|
r.db.Exec(fmt.Sprintf("UPDATE %s SET id = ? WHERE id = ?", tableName), squatterID, newID)
|
|
|
|
if tableName == "comandas" {
|
|
r.UpdateFK("product_comandas", "comanda_id", newID, squatterID)
|
|
r.UpdateFK("orders", "id_comanda", newID, squatterID)
|
|
r.UpdateFK("payments", "comanda_id", newID, squatterID)
|
|
} else if tableName == "product_comandas" {
|
|
r.UpdateFK("orders", "product_comanda_id", newID, squatterID)
|
|
}
|
|
}
|
|
|
|
return r.UpdateID(tableName, oldID, newID)
|
|
}
|
|
|
|
func (r *Repository) UpdateID(tableName string, oldID, newID uint) error {
|
|
return r.db.Exec(fmt.Sprintf("UPDATE %s SET id = ? WHERE id = ?", tableName), newID, oldID).Error
|
|
}
|
|
|
|
func (r *Repository) UpdateFK(tableName, fkColumn string, oldID, newID uint) error {
|
|
return r.db.Exec(fmt.Sprintf("UPDATE %s SET %s = ? WHERE %s = ?", tableName, fkColumn, fkColumn), newID, oldID).Error
|
|
}
|
|
|
|
// User
|
|
func (r *Repository) GetUserByUsername(username string) (*models.User, error) {
|
|
var user models.User
|
|
err := r.db.Where("username = ?", username).First(&user).Error
|
|
return &user, err
|
|
}
|
|
|
|
func (r *Repository) SaveUser(user *models.User) error {
|
|
return r.db.Save(user).Error
|
|
}
|
|
|
|
func (r *Repository) UpdateComandaStatus(id uint, status string) error {
|
|
return r.db.Model(&models.Comanda{}).Where("id = ?", id).Updates(map[string]interface{}{"status": status, "sincronizado": false}).Error
|
|
}
|
|
|
|
func (r *Repository) ClearComandaItems(comandaID uint) error {
|
|
return r.db.Where("comanda_id = ?", comandaID).Delete(&models.ProductComanda{}).Error
|
|
}
|
|
|
|
func (r *Repository) GetLastSyncID() int {
|
|
var state models.SyncState
|
|
r.db.FirstOrCreate(&state)
|
|
return state.LastSyncID
|
|
}
|
|
|
|
func (r *Repository) SaveLastSyncID(id int) {
|
|
r.db.Model(&models.SyncState{}).Where("id = ?", 1).Update("last_sync_id", id)
|
|
}
|
|
|
|
func (r *Repository) GetUnsyncedComandas() ([]models.Comanda, error) {
|
|
var results []models.Comanda
|
|
err := r.db.Where("sincronizado = ?", false).Find(&results).Error
|
|
return results, err
|
|
}
|
|
|
|
func (r *Repository) GetUnsyncedItems() ([]models.ProductComanda, error) {
|
|
var results []models.ProductComanda
|
|
err := r.db.Where("sincronizado = ?", false).Find(&results).Error
|
|
return results, err
|
|
}
|
|
|
|
func (r *Repository) GetUnsyncedOrders() ([]models.Order, error) {
|
|
var results []models.Order
|
|
err := r.db.Where("sincronizado = ?", false).Find(&results).Error
|
|
return results, err
|
|
}
|
|
|
|
func (r *Repository) GetUnsyncedPayments() ([]models.Payment, error) {
|
|
var results []models.Payment
|
|
err := r.db.Where("sincronizado = ?", false).Find(&results).Error
|
|
return results, err
|
|
}
|
|
|
|
func (r *Repository) GetUnsyncedProducts() ([]models.Product, error) {
|
|
var results []models.Product
|
|
err := r.db.Where("sincronizado = ?", false).Find(&results).Error
|
|
return results, err
|
|
}
|
|
|
|
func (r *Repository) GetComandaToSync(id uint, dest *models.Comanda) error {
|
|
return r.db.First(dest, id).Error
|
|
}
|
|
|
|
func (r *Repository) GetItemToSync(id uint, dest *models.ProductComanda) error {
|
|
return r.db.First(dest, id).Error
|
|
}
|
|
|
|
func (r *Repository) GetPaymentToSync(id uint, dest *models.Payment) error {
|
|
return r.db.First(dest, id).Error
|
|
}
|
|
|
|
func (r *Repository) GetProductToSync(id uint, dest *models.Product) error {
|
|
return r.db.First(dest, id).Error
|
|
}
|
|
|
|
func (r *Repository) GetOrderToSync(id uint, dest *models.Order) error {
|
|
return r.db.First(dest, id).Error
|
|
}
|
|
|
|
func (r *Repository) DeleteByID(modelName string, id uint) error {
|
|
var model interface{}
|
|
switch modelName {
|
|
case "Product":
|
|
model = &models.Product{}
|
|
case "Comanda":
|
|
model = &models.Comanda{}
|
|
case "ProductComanda":
|
|
model = &models.ProductComanda{}
|
|
case "Order":
|
|
model = &models.Order{}
|
|
case "Client":
|
|
model = &models.Client{}
|
|
case "Categories":
|
|
model = &models.Category{}
|
|
case "Mesa":
|
|
model = &models.Mesa{}
|
|
case "Payments":
|
|
model = &models.Payment{}
|
|
default:
|
|
return nil
|
|
}
|
|
return r.db.Delete(model, id).Error
|
|
}
|
|
|
|
func (r *Repository) UpdateComandaFields(id uint, updates map[string]interface{}) error {
|
|
mappedUpdates := make(map[string]interface{})
|
|
for k, v := range updates {
|
|
switch k {
|
|
case "mesa":
|
|
mappedUpdates["mesa_id"] = v
|
|
case "user":
|
|
mappedUpdates["user_id"] = v
|
|
case "client":
|
|
mappedUpdates["client_id"] = v
|
|
case "type_pay":
|
|
mappedUpdates["type_pay_id"] = v
|
|
default:
|
|
mappedUpdates[k] = v
|
|
}
|
|
}
|
|
|
|
// Mark as unsynced so the background worker pushes the update
|
|
mappedUpdates["sincronizado"] = false
|
|
|
|
return r.db.Model(&models.Comanda{}).Where("id = ?", id).Updates(mappedUpdates).Error
|
|
}
|