This commit is contained in:
aditya.siregar
2025-07-18 20:10:29 +07:00
parent 1bceae010b
commit 4f5950543e
511 changed files with 24132 additions and 34137 deletions
+102
View File
@@ -0,0 +1,102 @@
package entities
import (
"time"
"github.com/google/uuid"
)
// PaymentMethodAnalytics represents payment method analytics data
type PaymentMethodAnalytics struct {
PaymentMethodID uuid.UUID `json:"payment_method_id"`
PaymentMethodName string `json:"payment_method_name"`
PaymentMethodType string `json:"payment_method_type"`
TotalAmount float64 `json:"total_amount"`
OrderCount int64 `json:"order_count"`
PaymentCount int64 `json:"payment_count"`
}
// SalesAnalytics represents sales analytics data
type SalesAnalytics struct {
Date time.Time `json:"date"`
Sales float64 `json:"sales"`
Orders int64 `json:"orders"`
Items int64 `json:"items"`
Tax float64 `json:"tax"`
Discount float64 `json:"discount"`
NetSales float64 `json:"net_sales"`
}
// ProductAnalytics represents product analytics data
type ProductAnalytics struct {
ProductID uuid.UUID `json:"product_id"`
ProductName string `json:"product_name"`
CategoryID uuid.UUID `json:"category_id"`
CategoryName string `json:"category_name"`
QuantitySold int64 `json:"quantity_sold"`
Revenue float64 `json:"revenue"`
AveragePrice float64 `json:"average_price"`
OrderCount int64 `json:"order_count"`
}
// DashboardOverview represents dashboard overview data
type DashboardOverview struct {
TotalSales float64 `json:"total_sales"`
TotalOrders int64 `json:"total_orders"`
AverageOrderValue float64 `json:"average_order_value"`
TotalCustomers int64 `json:"total_customers"`
VoidedOrders int64 `json:"voided_orders"`
RefundedOrders int64 `json:"refunded_orders"`
}
// ProfitLossAnalytics represents profit and loss analytics data
type ProfitLossAnalytics struct {
Summary ProfitLossSummary `json:"summary"`
Data []ProfitLossData `json:"data"`
ProductData []ProductProfitData `json:"product_data"`
}
// ProfitLossSummary represents profit and loss summary data
type ProfitLossSummary struct {
TotalRevenue float64 `json:"total_revenue"`
TotalCost float64 `json:"total_cost"`
GrossProfit float64 `json:"gross_profit"`
GrossProfitMargin float64 `json:"gross_profit_margin"`
TotalTax float64 `json:"total_tax"`
TotalDiscount float64 `json:"total_discount"`
NetProfit float64 `json:"net_profit"`
NetProfitMargin float64 `json:"net_profit_margin"`
TotalOrders int64 `json:"total_orders"`
AverageProfit float64 `json:"average_profit"`
ProfitabilityRatio float64 `json:"profitability_ratio"`
}
// ProfitLossData represents profit and loss data by time period
type ProfitLossData struct {
Date time.Time `json:"date"`
Revenue float64 `json:"revenue"`
Cost float64 `json:"cost"`
GrossProfit float64 `json:"gross_profit"`
GrossProfitMargin float64 `json:"gross_profit_margin"`
Tax float64 `json:"tax"`
Discount float64 `json:"discount"`
NetProfit float64 `json:"net_profit"`
NetProfitMargin float64 `json:"net_profit_margin"`
Orders int64 `json:"orders"`
}
// ProductProfitData represents profit data for individual products
type ProductProfitData struct {
ProductID uuid.UUID `json:"product_id"`
ProductName string `json:"product_name"`
CategoryID uuid.UUID `json:"category_id"`
CategoryName string `json:"category_name"`
QuantitySold int64 `json:"quantity_sold"`
Revenue float64 `json:"revenue"`
Cost float64 `json:"cost"`
GrossProfit float64 `json:"gross_profit"`
GrossProfitMargin float64 `json:"gross_profit_margin"`
AveragePrice float64 `json:"average_price"`
AverageCost float64 `json:"average_cost"`
ProfitPerUnit float64 `json:"profit_per_unit"`
}
+56
View File
@@ -0,0 +1,56 @@
package entities
import (
"database/sql/driver"
"encoding/json"
"errors"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Metadata map[string]interface{}
func (m Metadata) Value() (driver.Value, error) {
return json.Marshal(m)
}
func (m *Metadata) Scan(value interface{}) error {
if value == nil {
*m = make(Metadata)
return nil
}
bytes, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(bytes, m)
}
type Category struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
Description *string `gorm:"type:text" json:"description"`
BusinessType string `gorm:"size:50;default:'restaurant'" json:"business_type"`
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
Products []Product `gorm:"foreignKey:CategoryID" json:"products,omitempty"`
}
func (c *Category) BeforeCreate(tx *gorm.DB) error {
if c.ID == uuid.Nil {
c.ID = uuid.New()
}
return nil
}
func (Category) TableName() string {
return "categories"
}
+36
View File
@@ -0,0 +1,36 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Customer struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
Name string `gorm:"not null;size:255" json:"name" validate:"required"`
Email *string `gorm:"size:255;uniqueIndex" json:"email,omitempty"`
Phone *string `gorm:"size:20" json:"phone,omitempty"`
Address *string `gorm:"size:500" json:"address,omitempty"`
IsDefault bool `gorm:"default:false" json:"is_default"`
IsActive bool `gorm:"default:true" json:"is_active"`
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
Orders []Order `gorm:"foreignKey:CustomerID" json:"orders,omitempty"`
}
func (c *Customer) BeforeCreate(tx *gorm.DB) error {
if c.ID == uuid.Nil {
c.ID = uuid.New()
}
return nil
}
func (Customer) TableName() string {
return "customers"
}
+26
View File
@@ -0,0 +1,26 @@
package entities
import "gorm.io/gorm"
func GetAllEntities() []interface{} {
return []interface{}{
&Organization{},
&Outlet{},
&OutletSetting{},
&User{},
&Category{},
&Product{},
&ProductVariant{},
&Inventory{},
&Order{},
&OrderItem{},
&PaymentMethod{},
&Payment{},
&Customer{},
// Analytics entities are not database tables, they are query results
}
}
func AutoMigrate(db *gorm.DB) error {
return db.AutoMigrate(GetAllEntities()...)
}
+28
View File
@@ -0,0 +1,28 @@
package entities
import (
"time"
"github.com/google/uuid"
)
type File struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrganizationID uuid.UUID `gorm:"type:uuid;not null" json:"organization_id"`
UserID uuid.UUID `gorm:"type:uuid;not null" json:"user_id"`
FileName string `gorm:"size:255;not null" json:"file_name"`
OriginalName string `gorm:"size:255;not null" json:"original_name"`
FileURL string `gorm:"size:500;not null" json:"file_url"`
FileSize int64 `gorm:"not null" json:"file_size"`
MimeType string `gorm:"size:100;not null" json:"mime_type"`
FileType string `gorm:"size:50;not null" json:"file_type"` // image, document, video, etc.
UploadPath string `gorm:"size:500;not null" json:"upload_path"`
IsPublic bool `gorm:"default:true" json:"is_public"`
Metadata Metadata `gorm:"type:jsonb" json:"metadata"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}
func (File) TableName() string {
return "files"
}
+42
View File
@@ -0,0 +1,42 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Inventory struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OutletID uuid.UUID `gorm:"type:uuid;not null;index" json:"outlet_id" validate:"required"`
ProductID uuid.UUID `gorm:"type:uuid;not null;index" json:"product_id" validate:"required"`
Quantity int `gorm:"not null;default:0" json:"quantity" validate:"min=0"`
ReorderLevel int `gorm:"default:0" json:"reorder_level" validate:"min=0"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Outlet Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
Product Product `gorm:"foreignKey:ProductID" json:"product,omitempty"`
}
func (i *Inventory) BeforeCreate(tx *gorm.DB) error {
if i.ID == uuid.Nil {
i.ID = uuid.New()
}
return nil
}
func (Inventory) TableName() string {
return "inventory"
}
func (i *Inventory) IsLowStock() bool {
return i.Quantity <= i.ReorderLevel
}
func (i *Inventory) UpdateQuantity(delta int) {
i.Quantity += delta
if i.Quantity < 0 {
i.Quantity = 0
}
}
+110
View File
@@ -0,0 +1,110 @@
package entities
import (
"fmt"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type OrderType string
type OrderStatus string
type PaymentStatus string
const (
OrderTypeDineIn OrderType = "dine_in"
OrderTypeTakeout OrderType = "takeout"
OrderTypeDelivery OrderType = "delivery"
)
const (
OrderStatusPending OrderStatus = "pending"
OrderStatusPreparing OrderStatus = "preparing"
OrderStatusReady OrderStatus = "ready"
OrderStatusCompleted OrderStatus = "completed"
OrderStatusCancelled OrderStatus = "cancelled"
)
const (
PaymentStatusPending PaymentStatus = "pending"
PaymentStatusCompleted PaymentStatus = "completed"
PaymentStatusFailed PaymentStatus = "failed"
PaymentStatusRefunded PaymentStatus = "refunded"
PaymentStatusPartiallyRefunded PaymentStatus = "partial-refunded"
)
type Order struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
OutletID uuid.UUID `gorm:"type:uuid;not null;index" json:"outlet_id" validate:"required"`
UserID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_id" validate:"required"`
CustomerID *uuid.UUID `gorm:"type:uuid;index" json:"customer_id"`
OrderNumber string `gorm:"uniqueIndex;not null;size:50" json:"order_number" validate:"required"`
TableNumber *string `gorm:"size:20" json:"table_number"`
OrderType OrderType `gorm:"not null;size:50" json:"order_type" validate:"required,oneof=dine_in takeout delivery"`
Status OrderStatus `gorm:"default:'pending';size:50" json:"status"`
Subtotal float64 `gorm:"type:decimal(10,2);not null" json:"subtotal" validate:"required,min=0"`
TaxAmount float64 `gorm:"type:decimal(10,2);not null" json:"tax_amount" validate:"required,min=0"`
DiscountAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"discount_amount" validate:"min=0"`
TotalAmount float64 `gorm:"type:decimal(10,2);not null" json:"total_amount" validate:"required,min=0"`
TotalCost float64 `gorm:"type:decimal(10,2);default:0.00" json:"total_cost"`
PaymentStatus PaymentStatus `gorm:"default:'pending';size:50" json:"payment_status"`
RefundAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"refund_amount"`
IsVoid bool `gorm:"default:false" json:"is_void"`
IsRefund bool `gorm:"default:false" json:"is_refund"`
VoidReason *string `gorm:"size:255" json:"void_reason,omitempty"`
VoidedAt *time.Time `gorm:"" json:"voided_at,omitempty"`
VoidedBy *uuid.UUID `gorm:"type:uuid" json:"voided_by,omitempty"`
RefundReason *string `gorm:"size:255" json:"refund_reason,omitempty"`
RefundedAt *time.Time `gorm:"" json:"refunded_at,omitempty"`
RefundedBy *uuid.UUID `gorm:"type:uuid" json:"refunded_by,omitempty"`
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
Outlet Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
User User `gorm:"foreignKey:UserID" json:"user,omitempty"`
OrderItems []OrderItem `gorm:"foreignKey:OrderID" json:"order_items,omitempty"`
Payments []Payment `gorm:"foreignKey:OrderID" json:"payments,omitempty"`
}
func (o *Order) BeforeCreate(tx *gorm.DB) error {
if o.ID == uuid.Nil {
o.ID = uuid.New()
}
if o.OrderNumber == "" {
timestamp := time.Now().Unix()
o.OrderNumber = fmt.Sprintf("ORD/%d", timestamp)
}
return nil
}
func (Order) TableName() string {
return "orders"
}
func (o *Order) CanBeModified() bool {
return o.Status == OrderStatusPending
}
func (o *Order) CanBeCancelled() bool {
return o.Status != OrderStatusCompleted && o.Status != OrderStatusCancelled
}
func (o *Order) GetTotalPaid() float64 {
var total float64
for _, payment := range o.Payments {
if payment.Status == PaymentTransactionStatusCompleted {
total += payment.Amount
}
}
return total
}
func (o *Order) IsFullyPaid() bool {
return o.GetTotalPaid() >= o.TotalAmount
}
+89
View File
@@ -0,0 +1,89 @@
package entities
import (
"database/sql/driver"
"encoding/json"
"errors"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Modifiers []map[string]interface{}
func (m Modifiers) Value() (driver.Value, error) {
return json.Marshal(m)
}
func (m *Modifiers) Scan(value interface{}) error {
if value == nil {
*m = make(Modifiers, 0)
return nil
}
bytes, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(bytes, m)
}
type OrderItemStatus string
const (
OrderItemStatusPending OrderItemStatus = "pending"
OrderItemStatusPreparing OrderItemStatus = "preparing"
OrderItemStatusReady OrderItemStatus = "ready"
OrderItemStatusServed OrderItemStatus = "served"
OrderItemStatusCancelled OrderItemStatus = "cancelled"
)
type OrderItem struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrderID uuid.UUID `gorm:"type:uuid;not null;index" json:"order_id" validate:"required"`
ProductID uuid.UUID `gorm:"type:uuid;not null;index" json:"product_id" validate:"required"`
ProductVariantID *uuid.UUID `gorm:"type:uuid;index" json:"product_variant_id"`
Quantity int `gorm:"not null" json:"quantity" validate:"required,min=1"`
UnitPrice float64 `gorm:"type:decimal(10,2);not null" json:"unit_price" validate:"required,min=0"`
TotalPrice float64 `gorm:"type:decimal(10,2);not null" json:"total_price" validate:"required,min=0"`
UnitCost float64 `gorm:"type:decimal(10,2);default:0.00" json:"unit_cost"`
TotalCost float64 `gorm:"type:decimal(10,2);default:0.00" json:"total_cost"`
RefundAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"refund_amount"`
RefundQuantity int `gorm:"default:0" json:"refund_quantity"`
IsPartiallyRefunded bool `gorm:"default:false" json:"is_partially_refunded"`
IsFullyRefunded bool `gorm:"default:false" json:"is_fully_refunded"`
RefundReason *string `gorm:"size:255" json:"refund_reason,omitempty"`
RefundedAt *time.Time `gorm:"" json:"refunded_at,omitempty"`
RefundedBy *uuid.UUID `gorm:"type:uuid" json:"refunded_by,omitempty"`
Modifiers Modifiers `gorm:"type:jsonb;default:'[]'" json:"modifiers"`
Notes *string `gorm:"size:500" json:"notes,omitempty"`
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
Status OrderItemStatus `gorm:"default:'pending';size:50" json:"status"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Order Order `gorm:"foreignKey:OrderID" json:"order,omitempty"`
Product Product `gorm:"foreignKey:ProductID" json:"product,omitempty"`
ProductVariant *ProductVariant `gorm:"foreignKey:ProductVariantID" json:"product_variant,omitempty"`
}
func (oi *OrderItem) BeforeCreate(tx *gorm.DB) error {
if oi.ID == uuid.Nil {
oi.ID = uuid.New()
}
return nil
}
func (OrderItem) TableName() string {
return "order_items"
}
func (oi *OrderItem) CalculateTotalPrice() {
oi.TotalPrice = float64(oi.Quantity) * oi.UnitPrice
}
func (oi *OrderItem) CanBeModified() bool {
return oi.Status == OrderItemStatusPending
}
+33
View File
@@ -0,0 +1,33 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type OrderSequence struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id"`
OutletID uuid.UUID `gorm:"type:uuid;not null;index" json:"outlet_id"`
Year int `gorm:"not null" json:"year"`
Month int `gorm:"not null" json:"month"`
SequenceNumber int `gorm:"not null;default:0" json:"sequence_number"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
Outlet Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
}
func (os *OrderSequence) BeforeCreate(tx *gorm.DB) error {
if os.ID == uuid.Nil {
os.ID = uuid.New()
}
return nil
}
func (OrderSequence) TableName() string {
return "order_sequences"
}
+34
View File
@@ -0,0 +1,34 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Organization struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
Email *string `gorm:"size:255" json:"email" validate:"omitempty,email"`
PhoneNumber *string `gorm:"size:20" json:"phone_number" validate:"omitempty"`
PlanType string `gorm:"not null;size:50" json:"plan_type" validate:"required,oneof=basic premium enterprise"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Outlets []Outlet `gorm:"foreignKey:OrganizationID" json:"outlets,omitempty"`
Users []User `gorm:"foreignKey:OrganizationID" json:"users,omitempty"`
}
func (o *Organization) BeforeCreate(tx *gorm.DB) error {
if o.ID == uuid.Nil {
id := uuid.New()
o.ID = id
}
return nil
}
func (Organization) TableName() string {
return "organizations"
}
+38
View File
@@ -0,0 +1,38 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Outlet struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
Address *string `gorm:"type:text" json:"address"`
Timezone *string `gorm:"size:50" json:"timezone"`
Currency string `gorm:"size:3;default:'USD'" json:"currency" validate:"len=3"`
TaxRate float64 `gorm:"type:decimal(5,4);default:0.0000" json:"tax_rate" validate:"min=0,max=1"`
IsActive bool `gorm:"default:true" json:"is_active"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
Users []User `gorm:"foreignKey:OutletID" json:"users,omitempty"`
Orders []Order `gorm:"foreignKey:OutletID" json:"orders,omitempty"`
Inventory []Inventory `gorm:"foreignKey:OutletID" json:"inventory,omitempty"`
Settings []OutletSetting `gorm:"foreignKey:OutletID" json:"settings,omitempty"`
}
func (o *Outlet) BeforeCreate(tx *gorm.DB) error {
if o.ID == uuid.Nil {
o.ID = uuid.New()
}
return nil
}
func (Outlet) TableName() string {
return "outlets"
}
+30
View File
@@ -0,0 +1,30 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type OutletSetting struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OutletID uuid.UUID `gorm:"type:uuid;not null;index" json:"outlet_id" validate:"required"`
Key string `gorm:"not null;size:255;index" json:"key" validate:"required,min=1,max=255"`
Value string `gorm:"type:text" json:"value"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Outlet Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
}
func (os *OutletSetting) BeforeCreate(tx *gorm.DB) error {
if os.ID == uuid.Nil {
os.ID = uuid.New()
}
return nil
}
func (OutletSetting) TableName() string {
return "outlet_settings"
}
+93
View File
@@ -0,0 +1,93 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type PaymentMethodType string
const (
PaymentMethodTypeCash PaymentMethodType = "cash"
PaymentMethodTypeCard PaymentMethodType = "card"
PaymentMethodTypeDigitalWallet PaymentMethodType = "digital_wallet"
)
type PaymentMethod struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
Name string `gorm:"not null;size:100" json:"name" validate:"required,min=1,max=100"`
Type PaymentMethodType `gorm:"not null;size:50" json:"type" validate:"required,oneof=cash card digital_wallet"`
Processor *string `gorm:"size:100" json:"processor"`
Configuration Metadata `gorm:"type:jsonb;default:'{}'" json:"configuration"`
IsActive bool `gorm:"default:true" json:"is_active"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
Payments []Payment `gorm:"foreignKey:PaymentMethodID" json:"payments,omitempty"`
}
func (pm *PaymentMethod) BeforeCreate(tx *gorm.DB) error {
if pm.ID == uuid.Nil {
pm.ID = uuid.New()
}
return nil
}
func (PaymentMethod) TableName() string {
return "payment_methods"
}
type PaymentTransactionStatus string
const (
PaymentTransactionStatusPending PaymentTransactionStatus = "pending"
PaymentTransactionStatusCompleted PaymentTransactionStatus = "completed"
PaymentTransactionStatusFailed PaymentTransactionStatus = "failed"
PaymentTransactionStatusRefunded PaymentTransactionStatus = "refunded"
)
type Payment struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrderID uuid.UUID `gorm:"type:uuid;not null;index" json:"order_id" validate:"required"`
PaymentMethodID uuid.UUID `gorm:"type:uuid;not null;index" json:"payment_method_id" validate:"required"`
Amount float64 `gorm:"type:decimal(10,2);not null" json:"amount" validate:"required,min=0"`
Status PaymentTransactionStatus `gorm:"default:'pending';size:50" json:"status"`
TransactionID *string `gorm:"size:255" json:"transaction_id"`
SplitNumber int `gorm:"default:1" json:"split_number"`
SplitTotal int `gorm:"default:1" json:"split_total"`
SplitDescription *string `gorm:"size:255" json:"split_description,omitempty"`
RefundAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"refund_amount"`
RefundReason *string `gorm:"size:255" json:"refund_reason,omitempty"`
RefundedAt *time.Time `gorm:"" json:"refunded_at,omitempty"`
RefundedBy *uuid.UUID `gorm:"type:uuid" json:"refunded_by,omitempty"`
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Order Order `gorm:"foreignKey:OrderID" json:"order,omitempty"`
PaymentMethod PaymentMethod `gorm:"foreignKey:PaymentMethodID" json:"payment_method,omitempty"`
PaymentOrderItems []PaymentOrderItem `gorm:"foreignKey:PaymentID" json:"payment_order_items,omitempty"`
}
func (p *Payment) BeforeCreate(tx *gorm.DB) error {
if p.ID == uuid.Nil {
p.ID = uuid.New()
}
return nil
}
func (Payment) TableName() string {
return "payments"
}
func (p *Payment) CanBeRefunded() bool {
return p.Status == PaymentTransactionStatusCompleted
}
func (p *Payment) IsSuccessful() bool {
return p.Status == PaymentTransactionStatusCompleted
}
+31
View File
@@ -0,0 +1,31 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type PaymentOrderItem struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
PaymentID uuid.UUID `gorm:"type:uuid;not null;index" json:"payment_id"`
OrderItemID uuid.UUID `gorm:"type:uuid;not null;index" json:"order_item_id"`
Amount float64 `gorm:"type:decimal(10,2);not null" json:"amount"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Payment Payment `gorm:"foreignKey:PaymentID" json:"payment,omitempty"`
OrderItem OrderItem `gorm:"foreignKey:OrderItemID" json:"order_item,omitempty"`
}
func (poi *PaymentOrderItem) BeforeCreate(tx *gorm.DB) error {
if poi.ID == uuid.Nil {
poi.ID = uuid.New()
}
return nil
}
func (PaymentOrderItem) TableName() string {
return "payment_order_items"
}
+66
View File
@@ -0,0 +1,66 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Product struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
CategoryID uuid.UUID `gorm:"type:uuid;not null;index" json:"category_id" validate:"required"`
SKU *string `gorm:"size:100;index" json:"sku"`
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
Description *string `gorm:"type:text" json:"description"`
Price float64 `gorm:"type:decimal(10,2);not null" json:"price" validate:"required,min=0"`
Cost float64 `gorm:"type:decimal(10,2);default:0.00" json:"cost" validate:"min=0"`
BusinessType string `gorm:"size:50;default:'restaurant'" json:"business_type"`
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
IsActive bool `gorm:"default:true" json:"is_active"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
Category Category `gorm:"foreignKey:CategoryID" json:"category,omitempty"`
ProductVariants []ProductVariant `gorm:"foreignKey:ProductID" json:"variants,omitempty"`
Inventory []Inventory `gorm:"foreignKey:ProductID" json:"inventory,omitempty"`
OrderItems []OrderItem `gorm:"foreignKey:ProductID" json:"order_items,omitempty"`
}
func (p *Product) BeforeCreate(tx *gorm.DB) error {
if p.ID == uuid.Nil {
p.ID = uuid.New()
}
return nil
}
func (Product) TableName() string {
return "products"
}
type ProductVariant struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
ProductID uuid.UUID `gorm:"type:uuid;not null;index" json:"product_id" validate:"required"`
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
PriceModifier float64 `gorm:"type:decimal(10,2);default:0.00" json:"price_modifier"`
Cost float64 `gorm:"type:decimal(10,2);default:0.00" json:"cost" validate:"min=0"`
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Product Product `gorm:"foreignKey:ProductID" json:"product,omitempty"`
OrderItems []OrderItem `gorm:"foreignKey:ProductVariantID" json:"order_items,omitempty"`
}
func (pv *ProductVariant) BeforeCreate(tx *gorm.DB) error {
if pv.ID == uuid.Nil {
pv.ID = uuid.New()
}
return nil
}
func (ProductVariant) TableName() string {
return "product_variants"
}
+94
View File
@@ -0,0 +1,94 @@
package entities
import (
"database/sql/driver"
"encoding/json"
"errors"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type UserRole string
const (
RoleAdmin UserRole = "admin"
RoleManager UserRole = "manager"
RoleCashier UserRole = "cashier"
RoleWaiter UserRole = "waiter"
)
type Permissions map[string]interface{}
func (p Permissions) Value() (driver.Value, error) {
return json.Marshal(p)
}
func (p *Permissions) Scan(value interface{}) error {
if value == nil {
*p = make(Permissions)
return nil
}
bytes, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(bytes, p)
}
type User struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"`
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
Email string `gorm:"uniqueIndex;not null;size:255" json:"email" validate:"required,email"`
PasswordHash string `gorm:"not null;size:255" json:"-"`
Role UserRole `gorm:"not null;size:50" json:"role" validate:"required,oneof=admin manager cashier waiter"`
Permissions Permissions `gorm:"type:jsonb;default:'{}'" json:"permissions"`
IsActive bool `gorm:"default:true" json:"is_active"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
Outlet *Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
Orders []Order `gorm:"foreignKey:UserID" json:"orders,omitempty"`
}
func (u *User) BeforeCreate(tx *gorm.DB) error {
if u.ID == uuid.Nil {
u.ID = uuid.New()
}
return nil
}
func (User) TableName() string {
return "users"
}
func (u *User) HasPermission(permission string) bool {
if u.Role == RoleAdmin {
return true
}
if value, exists := u.Permissions[permission]; exists {
if hasPermission, ok := value.(bool); ok {
return hasPermission
}
}
return false
}
func (u *User) CanAccessOutlet(outletID uuid.UUID) bool {
if u.Role == RoleAdmin {
return true
}
if u.OutletID != nil && *u.OutletID == outletID {
return true
}
return false
}