File size: 15,990 Bytes
edcf070
 
 
 
 
 
 
 
 
 
 
 
ac5c922
edcf070
 
 
e79019b
edcf070
 
6fd3b19
 
 
 
10b6d0b
8879e0b
10b6d0b
 
 
 
 
7121ebc
c6a3ee4
 
88124cb
 
 
8879e0b
c6e89e6
 
 
10b6d0b
edcf070
 
 
 
 
 
ae76db4
17e3823
 
 
ae76db4
 
4774488
 
 
 
 
 
 
 
 
ae76db4
fb74e1c
 
 
 
 
77568d0
 
 
 
 
 
ea73154
 
d1cbed4
a66f5d3
 
 
 
 
 
 
 
 
 
 
edcf070
 
 
 
 
 
 
 
e79019b
938b985
edcf070
 
 
 
 
 
 
 
 
 
 
 
 
 
25eb4e0
 
e79019b
edcf070
 
ea73154
edcf070
 
 
 
25eb4e0
edcf070
 
 
 
 
 
 
 
 
25eb4e0
edcf070
 
 
 
 
25eb4e0
edcf070
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25eb4e0
 
edcf070
7121ebc
edcf070
 
 
 
 
 
 
 
 
 
ea73154
ae76db4
7121ebc
ae76db4
e70dcc5
 
a90354c
edcf070
7121ebc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
edcf070
 
 
 
25eb4e0
 
edcf070
 
 
 
 
 
 
 
 
 
 
 
 
 
4e8a43c
 
 
 
 
 
 
236d19a
4e8a43c
 
c6a3ee4
 
 
 
 
 
 
 
 
 
 
 
c6e89e6
 
 
 
 
 
 
 
 
 
 
 
c6a3ee4
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
package models

import (
	"time"
)

type Company struct {
	ID                uint           `gorm:"primaryKey" json:"id"`
	Name              string         `gorm:"type:varchar(100);not null" json:"name"`
	BankAccountNumber string         `gorm:"type:varchar(50)" json:"bank_account_number"`
	BankName          string         `gorm:"type:varchar(100)" json:"bank_name"`
	Address           string         `gorm:"type:varchar(255)" json:"address"`
	NPWP              string         `gorm:"type:varchar(50)" json:"npwp"`
	Email             string         `gorm:"type:varchar(100)" json:"email"`
	Phone             string         `gorm:"type:varchar(20)" json:"phone"`
	LogoURL           string         `gorm:"type:varchar(255)" json:"logo_url"`
	IsActive          bool           `json:"is_active"`
	FeePercentage     float64        `gorm:"type:float;default:0.0;not null" json:"fee_percentage"`
	ApprovedAt        *time.Time     `json:"approved_at"`
	TripayMerchantCode string         `gorm:"type:varchar(100)" json:"tripay_merchant_code"`
	TripayAPIKey       string         `gorm:"type:text" json:"tripay_api_key"`
	TripayPrivateKey   string         `gorm:"type:text" json:"tripay_private_key"`
	TripayProxyURL     string         `gorm:"type:text" json:"tripay_proxy_url"`
	CashFeeRules       string         `gorm:"type:text;default:'[]'" json:"cash_fee_rules"`
	QrisFeeRules       string         `gorm:"type:text;default:'[]'" json:"qris_fee_rules"`
	QrisFeePercentage  float64        `gorm:"type:float;default:1.7" json:"qris_fee_percentage"`
	QrisFeeFixed       int            `gorm:"default:500" json:"qris_fee_fixed"`
	QrisFeeMin         int            `gorm:"default:850" json:"qris_fee_min"`
	QrisMinTransaction int            `gorm:"default:10000" json:"qris_min_transaction"`
	AllowQrisBelowMin  bool           `gorm:"default:false" json:"allow_qris_below_min"`
	ChargeFeeBeforeDiscount bool      `gorm:"default:false" json:"charge_fee_before_discount"`
	WalletBalance      float64        `gorm:"type:float;default:0.0" json:"wallet_balance"`
	WalletLimit        float64        `gorm:"type:float;default:-50000.0" json:"wallet_limit"`
	EnableMember       bool           `gorm:"default:true" json:"enable_member"`
	EnableVoucher      bool           `gorm:"default:true" json:"enable_voucher"`
	EnableMultiBranch  bool           `gorm:"default:false" json:"enable_multi_branch"`
	MaxBranches        int            `gorm:"default:0" json:"max_branches"`
	EnableMultiKasir      bool           `gorm:"default:false" json:"enable_multi_kasir"`
	MaxCashiers           int            `gorm:"default:0" json:"max_cashiers"`
	EnforceSingleSession  bool           `gorm:"default:false" json:"enforce_single_session"`
	PointRules         []PointRule    `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"point_rules"`
	CreatedAt         time.Time      `gorm:"autoCreateTime" json:"created_at"`
	Branches          []Branch       `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"-"`
	Users             []User         `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"-"`
	Categories        []Category     `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"-"`
	Products          []Product      `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"-"`
	Orders            []Order        `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"-"`
	Members           []Member       `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"-"`
	PointHistories    []PointHistory `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"-"`
	WalletTransactions []WalletTransaction `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"-"`
	TopupRequests     []TopupRequest `gorm:"foreignKey:CompanyID;constraint:OnDelete:CASCADE" json:"-"`
}

type PointRule struct {
	ID          uint      `gorm:"primaryKey" json:"id"`
	CompanyID   uint      `gorm:"not null;index" json:"company_id"`
	MinAmount   int       `gorm:"not null" json:"min_amount"`
	PointReward int       `gorm:"not null" json:"point_reward"`
	CreatedAt   time.Time `gorm:"autoCreateTime" json:"created_at"`
	UpdatedAt   time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}

type Member struct {
	ID         uint      `gorm:"primaryKey" json:"id"`
	CompanyID  uint      `gorm:"not null;index" json:"company_id"`
	MemberCode string    `gorm:"column:member_id;type:varchar(50);not null;uniqueIndex:uq_company_member" json:"member_id"`
	Name       string    `gorm:"type:varchar(100);not null" json:"name"`
	Phone      string    `gorm:"type:varchar(20)" json:"phone"`
	Points        int       `gorm:"default:0" json:"points"`
	BranchID      *uint     `gorm:"index" json:"branch_id"`
	CreatedByID   *uint     `gorm:"index" json:"created_by_id"`
	CreatedByName string    `gorm:"type:varchar(100)" json:"created_by_name"`
	CreatedAt     time.Time `gorm:"autoCreateTime" json:"created_at"`
	Company       *Company  `gorm:"foreignKey:CompanyID" json:"company,omitempty"`
	Branch      *Branch   `gorm:"foreignKey:BranchID;constraint:OnDelete:SET NULL;" json:"branch,omitempty"`
	CreatedBy   *User     `gorm:"foreignKey:CreatedByID;constraint:OnDelete:SET NULL;" json:"created_by,omitempty"`
	PointHistories []PointHistory `gorm:"foreignKey:MemberID;constraint:OnDelete:CASCADE" json:"PointHistories"`
}

type PointHistory struct {
	ID          uint      `gorm:"primaryKey" json:"id"`
	CompanyID   uint      `gorm:"not null;index" json:"company_id"`
	MemberID    uint      `gorm:"not null;index" json:"member_id"`
	PointsDelta int       `gorm:"not null" json:"points_delta"` // e.g. +5 or -2
	Reason      string    `gorm:"type:varchar(255)" json:"reason"` // e.g., "Transaksi WP-123", "Penyesuaian Manual oleh Budi"
	CreatedAt   time.Time `gorm:"autoCreateTime" json:"created_at"`

	Company *Company `gorm:"foreignKey:CompanyID" json:"-"`
}

type Branch struct {
	ID             uint            `gorm:"primaryKey" json:"id"`
	CompanyID      uint            `gorm:"not null;index" json:"company_id"`
	Name           string          `gorm:"type:varchar(100);not null" json:"name"`
	Address        string          `gorm:"type:varchar(255)" json:"address"`
	Phone          string          `gorm:"type:varchar(20)" json:"phone"`
	IsActive       bool            `json:"is_active"`
	IsPointEnabled bool            `gorm:"default:true" json:"is_point_enabled"`
	CreatedAt      time.Time       `gorm:"autoCreateTime" json:"created_at"`
	Company        *Company        `gorm:"foreignKey:CompanyID" json:"company,omitempty"`
	Users          []User          `gorm:"foreignKey:BranchID;constraint:OnDelete:SET NULL" json:"-"`
	Orders         []Order         `gorm:"foreignKey:BranchID;constraint:OnDelete:SET NULL" json:"-"`
	BranchProducts []BranchProduct `gorm:"foreignKey:BranchID;constraint:OnDelete:CASCADE" json:"-"`
}

type User struct {
	ID        uint      `gorm:"primaryKey" json:"id"`
	Name      string    `gorm:"type:varchar(100);not null" json:"name"`
	Email     string    `gorm:"type:varchar(100);uniqueIndex;not null" json:"email"`
	Password  string    `gorm:"type:varchar(255);not null" json:"-"`
	Phone     string    `gorm:"type:varchar(20)" json:"phone"`
	Role      string    `gorm:"type:varchar(20);default:'kasir'" json:"role"` // "super_admin", "owner", "kasir"
	CompanyID *uint     `gorm:"index" json:"company_id"`
	BranchID  *uint     `gorm:"index" json:"branch_id"`
	IsActive  bool      `json:"is_active"`
	CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
	Company   *Company  `gorm:"foreignKey:CompanyID" json:"company,omitempty"`
	Branch    *Branch   `gorm:"foreignKey:BranchID;constraint:OnDelete:SET NULL;" json:"branch,omitempty"`
}

type Category struct {
	ID          uint      `gorm:"primaryKey" json:"id"`
	CompanyID   uint      `gorm:"not null;index" json:"company_id"`
	Name        string    `gorm:"type:varchar(100);not null" json:"name"`
	Description string    `gorm:"type:varchar(255)" json:"description"`
	CreatedAt   time.Time `gorm:"autoCreateTime" json:"created_at"`
	Company     *Company  `gorm:"foreignKey:CompanyID" json:"company,omitempty"`
	Products    []Product `gorm:"foreignKey:CategoryID" json:"products,omitempty"`
}

type Product struct {
	ID               uint            `gorm:"primaryKey" json:"id"`
	CompanyID        uint            `gorm:"not null;index" json:"company_id"`
	Name             string          `gorm:"type:varchar(200);not null" json:"name"`
	SKU              *string         `gorm:"type:varchar(50);uniqueIndex" json:"sku"`
	Price            int             `gorm:"not null" json:"price"`
	Stock            int             `gorm:"not null;default:0" json:"stock"`
	IsUnlimitedStock bool            `gorm:"default:false" json:"is_unlimited_stock"`
	CategoryID       *uint           `gorm:"index" json:"category_id"`
	ImageURL         string          `gorm:"type:text" json:"image_url"`
	IsActive         bool            `gorm:"default:true" json:"is_active"`
	CreatedAt        time.Time       `gorm:"autoCreateTime" json:"created_at"`
	UpdatedAt        time.Time       `gorm:"autoUpdateTime" json:"updated_at"`
	Company          *Company        `gorm:"foreignKey:CompanyID" json:"company,omitempty"`
	Category         *Category       `gorm:"foreignKey:CategoryID" json:"category,omitempty"`
	BranchProducts   []BranchProduct `gorm:"foreignKey:ProductID;constraint:OnDelete:CASCADE" json:"-"`
}

type BranchProduct struct {
	ID          uint    `gorm:"primaryKey" json:"id"`
	BranchID    uint    `gorm:"uniqueIndex:uq_branch_product;not null" json:"branch_id"`
	ProductID   uint    `gorm:"uniqueIndex:uq_branch_product;not null" json:"product_id"`
	IsAvailable bool    `gorm:"default:true" json:"is_available"`
	Branch      *Branch `gorm:"foreignKey:BranchID" json:"branch,omitempty"`
	Product     *Product `gorm:"foreignKey:ProductID" json:"product,omitempty"`
}

type Order struct {
	ID              uint        `gorm:"primaryKey" json:"id"`
	CompanyID       uint        `gorm:"not null;index" json:"company_id"`
	BranchID        *uint       `gorm:"index" json:"branch_id"`
	OrderNumber     string      `gorm:"type:varchar(50);not null;index" json:"order_number"`
	SubtotalAmount  int         `gorm:"not null;default:0" json:"subtotal_amount"`
	TotalAmount     int         `gorm:"not null;default:0" json:"total_amount"`
	PaidAmount      int         `gorm:"not null;default:0" json:"paid_amount"`
	ChangeAmount    int         `gorm:"not null;default:0" json:"change_amount"`
	PaymentMethod   string      `gorm:"type:varchar(20)" json:"payment_method"`
	PaymentStatus   string      `gorm:"type:varchar(20);default:'pending'" json:"payment_status"` // pending, paid, failed, expired, refunded, cancelled
	MidtransOrderID string      `gorm:"type:varchar(100)" json:"midtrans_order_id"`
	MidtransToken   string      `gorm:"type:varchar(255)" json:"midtrans_token"`
	PlatformFee     int         `gorm:"not null;default:0" json:"platform_fee"`
	CreatedAt       time.Time   `gorm:"autoCreateTime" json:"created_at"`
	Company         *Company    `gorm:"foreignKey:CompanyID" json:"company,omitempty"`
	Branch          *Branch     `gorm:"foreignKey:BranchID;constraint:OnDelete:SET NULL;" json:"branch,omitempty"`
	MemberID        *uint       `gorm:"index" json:"member_id"`
	Member          *Member     `gorm:"constraint:-" json:"member,omitempty"`
	ServedBy        string      `gorm:"type:varchar(100)" json:"served_by"`
	CustomerName    string      `gorm:"type:varchar(100)" json:"customer_name"`
	CustomerPhone   string      `gorm:"type:varchar(50)" json:"customer_phone"`
	PointsEarned    int         `gorm:"default:0" json:"points_earned"`
	Items           []OrderItem `gorm:"foreignKey:OrderID;constraint:OnDelete:CASCADE" json:"items"`
	VoucherID       *uint       `gorm:"index" json:"voucher_id"`
	Voucher         *Voucher    `gorm:"constraint:-" json:"voucher,omitempty"`
	DiscountAmount  int         `gorm:"default:0" json:"discount_amount"`
	PointsUsed      int         `gorm:"default:0" json:"points_used"`
}

type Voucher struct {
	ID             uint      `gorm:"primaryKey" json:"id"`
	CompanyID      uint      `gorm:"not null;index" json:"company_id"`
	BranchID       *uint     `gorm:"index" json:"branch_id"`
	Name           string    `gorm:"type:varchar(100);not null" json:"name"`
	DiscountValue  int       `gorm:"not null;default:0" json:"discount_value"`
	PointCost      int       `gorm:"not null;default:0" json:"point_cost"`
	MinPurchase    int       `gorm:"not null;default:0" json:"min_purchase"`
	IsActive       bool      `gorm:"default:true" json:"is_active"`
	CreatedAt      time.Time `gorm:"autoCreateTime" json:"created_at"`
	UpdatedAt      time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}

type OrderItem struct {
	ID        uint     `gorm:"primaryKey" json:"id"`
	OrderID   uint     `gorm:"not null;index" json:"order_id"`
	ProductID uint     `gorm:"not null;index" json:"product_id"`
	Quantity  int      `gorm:"not null;default:1" json:"quantity"`
	UnitPrice int      `gorm:"not null" json:"unit_price"`
	Subtotal  int      `gorm:"not null" json:"subtotal"`
	Product   *Product `gorm:"foreignKey:ProductID" json:"product,omitempty"`
}

type OTP struct {
	ID          uint      `gorm:"primaryKey" json:"id"`
	PhoneNumber string    `gorm:"type:varchar(20);not null;index" json:"phone_number"`
	OTPCode     string    `gorm:"type:varchar(10);not null" json:"otp_code"`
	IsVerified  bool      `gorm:"default:false" json:"is_verified"`
	CreatedAt   time.Time `gorm:"autoCreateTime" json:"created_at"`
	ExpiresAt   time.Time `gorm:"not null" json:"expires_at"`
}

type Setting struct {
	ID                 uint      `gorm:"primaryKey" json:"id"`
	TripayMerchantCode string    `gorm:"type:varchar(100)" json:"tripay_merchant_code"`
	TripayAPIKey       string    `gorm:"type:text" json:"tripay_api_key"`
	TripayPrivateKey   string    `gorm:"type:text" json:"tripay_private_key"`
	TripayProxyURL     string    `gorm:"type:text" json:"tripay_proxy_url"`
	TripayPaymentMethod string    `gorm:"type:varchar(50);default:'QRIS'" json:"tripay_payment_method"`
	UpdatedAt          time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}

type WalletTransaction struct {
	ID        uint      `gorm:"primaryKey" json:"id"`
	CompanyID uint      `gorm:"not null;index" json:"company_id"`
	Amount    float64   `gorm:"not null" json:"amount"`
	Type      string    `gorm:"type:varchar(50);not null" json:"type"` // "cash_fee", "topup_qris", "topup_manual", "admin_adjustment"
	RefID     string    `gorm:"type:varchar(100)" json:"ref_id"`
	Desc      string    `gorm:"type:varchar(255)" json:"desc"`
	CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
	Company   *Company  `gorm:"foreignKey:CompanyID" json:"company,omitempty"`
}

// UserSession tracks active login sessions for single-session enforcement
type UserSession struct {
	ID           uint      `gorm:"primaryKey" json:"id"`
	UserID       uint      `gorm:"not null;index" json:"user_id"`
	SessionToken string    `gorm:"type:varchar(64);not null;uniqueIndex" json:"session_token"`
	UserAgent    string    `gorm:"type:varchar(255)" json:"user_agent"`
	IPAddress    string    `gorm:"type:varchar(45)" json:"ip_address"`
	ExpiresAt    time.Time `gorm:"not null" json:"expires_at"`
	CreatedAt    time.Time `gorm:"autoCreateTime" json:"created_at"`
	User         *User     `gorm:"foreignKey:UserID;constraint:OnDelete:CASCADE" json:"-"`
}

type TopupRequest struct {
	ID        uint      `gorm:"primaryKey" json:"id"`
	CompanyID uint      `gorm:"not null;index" json:"company_id"`
	Amount    float64   `gorm:"not null" json:"amount"`
	ProofURL  string    `gorm:"type:varchar(255);not null" json:"proof_url"`
	Status    string    `gorm:"type:varchar(20);default:'pending'" json:"status"` // pending, approved, rejected
	CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
	UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
	Company   *Company  `gorm:"foreignKey:CompanyID" json:"company,omitempty"`
}