feat: RRBEC Local Server - Go backend with Django sync
- 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
This commit is contained in:
177
rrbec_server/internal/models/models.go
Normal file
177
rrbec_server/internal/models/models.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Custom type to handle Price as string or float from JSON
|
||||
type Price float64
|
||||
|
||||
func (p *Price) UnmarshalJSON(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
s := string(data)
|
||||
// Remove quotes if it's a string
|
||||
if s[0] == '"' {
|
||||
s = s[1 : len(s)-1]
|
||||
}
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*p = Price(f)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Base model with UUID and sync fields
|
||||
type Base struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
UUID string `gorm:"uniqueIndex" json:"uuid"`
|
||||
Sincronizado bool `gorm:"default:false" json:"sincronizado"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (b *Base) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
if b.UUID == "" {
|
||||
b.UUID = uuid.New().String()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Mesa struct {
|
||||
Base
|
||||
Name string `json:"name"`
|
||||
Location string `json:"location"`
|
||||
Active bool `gorm:"default:false" json:"active"`
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
Base
|
||||
Name string `json:"name"`
|
||||
Debt Price `gorm:"default:0" json:"debt"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Active bool `gorm:"default:true" json:"active"`
|
||||
Contact string `json:"contact"`
|
||||
}
|
||||
|
||||
type Category struct {
|
||||
Base
|
||||
Name string `json:"name"`
|
||||
Active bool `gorm:"default:true" json:"active"`
|
||||
}
|
||||
|
||||
type Product struct {
|
||||
Base
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Image string `json:"image"` // URL or Path
|
||||
Price Price `json:"price"`
|
||||
Quantity int `gorm:"default:0" json:"quantity"`
|
||||
CategoryID uint `gorm:"column:category" json:"category"`
|
||||
Cuisine bool `gorm:"default:false" json:"cuisine"`
|
||||
Active bool `gorm:"default:true" json:"active"`
|
||||
UnitOfMeasure *uint `gorm:"column:unit_of_measure" json:"unit_of_measure"`
|
||||
}
|
||||
|
||||
type ProductComponent struct {
|
||||
Base
|
||||
CompositeProductID uint `json:"composite_product"`
|
||||
ComponentProductID uint `json:"component_product"`
|
||||
QuantityRequired float64 `json:"quantity_required"`
|
||||
}
|
||||
|
||||
type Comanda struct {
|
||||
Base
|
||||
MesaID uint `json:"mesa"`
|
||||
UserID uint `json:"user"`
|
||||
TypePayID *uint `json:"type_pay"`
|
||||
ClientID *uint `json:"client"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"` // OPEN, CLOSED, FIADO
|
||||
DtOpen time.Time `json:"dt_open"`
|
||||
DtClose *time.Time `json:"dt_close"`
|
||||
|
||||
// Nested items from Django (not stored in coma nda table)
|
||||
Items []ProductComanda `gorm:"-" json:"items"`
|
||||
}
|
||||
|
||||
type ProductComanda struct {
|
||||
Base
|
||||
ComandaID uint `json:"comanda"`
|
||||
ProductID uint `json:"product"`
|
||||
ProductName string `gorm:"-" json:"product_name"` // Read-only
|
||||
ProductPrice Price `gorm:"-" json:"product_price"` // Read-only
|
||||
DateTime time.Time `json:"data_time"`
|
||||
Applicant string `json:"applicant"`
|
||||
Obs string `gorm:"-" json:"obs"` // From Order
|
||||
}
|
||||
|
||||
type Order struct {
|
||||
Base
|
||||
ProductComandaID *uint `json:"productComanda"`
|
||||
ProductID uint `json:"id_product"`
|
||||
ComandaID uint `json:"id_comanda"`
|
||||
Obs string `json:"obs"`
|
||||
Queue time.Time `json:"queue"`
|
||||
Preparing *time.Time `json:"preparing"`
|
||||
Finished *time.Time `json:"finished"`
|
||||
Delivered *time.Time `json:"delivered"`
|
||||
Canceled *time.Time `json:"canceled"`
|
||||
}
|
||||
|
||||
func (o *Order) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
// Call Base.BeforeCreate to generate UUID
|
||||
if err := o.Base.BeforeCreate(tx); err != nil {
|
||||
return err
|
||||
}
|
||||
if o.Queue.IsZero() {
|
||||
o.Queue = time.Now()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type TypePay struct {
|
||||
Base
|
||||
Name string `json:"name"`
|
||||
Active bool `gorm:"default:true" json:"active"`
|
||||
}
|
||||
|
||||
type Payment struct {
|
||||
Base
|
||||
Value Price `json:"value"`
|
||||
TypePayID uint `json:"type_pay"`
|
||||
ComandaID uint `json:"comanda"`
|
||||
ClientID *uint `json:"client"`
|
||||
Description string `json:"description"`
|
||||
DateTime time.Time `json:"datetime"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Base
|
||||
Username string `gorm:"uniqueIndex" json:"username"`
|
||||
Password string `json:"password"`
|
||||
Email string `json:"email"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
IsStaff bool `json:"is_staff"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
type SyncState struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
LastSyncID int `gorm:"default:0"`
|
||||
}
|
||||
|
||||
type ChangeLog struct {
|
||||
ID int `json:"id"`
|
||||
ModelName string `json:"model_name"`
|
||||
ObjectID uint `json:"object_id"`
|
||||
Action string `json:"action"` // SAVE or DELETE
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
Reference in New Issue
Block a user