feat: cash advance
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateCashAdvanceRequest struct {
|
||||
// OutletID falls back to the caller's outlet when omitted; an advance is cash out
|
||||
// of one drawer, so one of the two has to be known.
|
||||
OutletID *uuid.UUID `json:"outlet_id,omitempty" validate:"omitempty"`
|
||||
CodeNumber string `json:"code_number" validate:"required,min=1,max=50"`
|
||||
TeamScope string `json:"team_scope" validate:"required,oneof=category central"`
|
||||
TeamCategoryID *uuid.UUID `json:"team_category_id,omitempty" validate:"omitempty"`
|
||||
Amount float64 `json:"amount" validate:"required,gt=0"`
|
||||
IssuedDate string `json:"issued_date" validate:"required"` // Format: YYYY-MM-DD
|
||||
DueDate *string `json:"due_date,omitempty" validate:"omitempty"` // Format: YYYY-MM-DD
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft approved rejected cancelled"`
|
||||
Description *string `json:"description,omitempty" validate:"omitempty"`
|
||||
}
|
||||
|
||||
type UpdateCashAdvanceRequest struct {
|
||||
CodeNumber *string `json:"code_number,omitempty" validate:"omitempty,min=1,max=50"`
|
||||
// An advance always belongs to a team, so team_scope can be moved but not cleared.
|
||||
TeamScope *string `json:"team_scope,omitempty" validate:"omitempty,oneof=category central"`
|
||||
TeamCategoryID *uuid.UUID `json:"team_category_id,omitempty" validate:"omitempty"`
|
||||
Amount *float64 `json:"amount,omitempty" validate:"omitempty,gt=0"`
|
||||
ReturnedAmount *float64 `json:"returned_amount,omitempty" validate:"omitempty,gte=0"`
|
||||
IssuedDate *string `json:"issued_date,omitempty" validate:"omitempty"`
|
||||
DueDate *string `json:"due_date,omitempty" validate:"omitempty"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft approved rejected cancelled"`
|
||||
Description *string `json:"description,omitempty" validate:"omitempty"`
|
||||
}
|
||||
|
||||
type CashAdvanceResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
OutletID uuid.UUID `json:"outlet_id"`
|
||||
CodeNumber string `json:"code_number"`
|
||||
TeamScope string `json:"team_scope"`
|
||||
TeamCategoryID *uuid.UUID `json:"team_category_id"`
|
||||
Amount float64 `json:"amount"`
|
||||
SettledAmount float64 `json:"settled_amount"`
|
||||
ReturnedAmount float64 `json:"returned_amount"`
|
||||
RemainingAmount float64 `json:"remaining_amount"`
|
||||
SettlementStatus string `json:"settlement_status"`
|
||||
IssuedDate time.Time `json:"issued_date"`
|
||||
DueDate *time.Time `json:"due_date"`
|
||||
Status string `json:"status"`
|
||||
Description *string `json:"description"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Team *PurchaseTeamResponse `json:"team,omitempty"`
|
||||
Settlements []CashAdvanceSettlementResponse `json:"settlements,omitempty"`
|
||||
}
|
||||
|
||||
// CashAdvanceSettlementResponse is one purchase order or expense paid out of the
|
||||
// advance.
|
||||
type CashAdvanceSettlementResponse struct {
|
||||
Type string `json:"type"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
Number string `json:"number"`
|
||||
Date time.Time `json:"date"`
|
||||
Amount float64 `json:"amount"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type ListCashAdvancesRequest struct {
|
||||
Page int `json:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
Search string `json:"search,omitempty"`
|
||||
Status string `json:"status,omitempty" validate:"omitempty,oneof=draft approved rejected cancelled"`
|
||||
// SettlementStatus filters on how much of the cash has been accounted for,
|
||||
// which is derived from the spending charged to the advance rather than stored.
|
||||
SettlementStatus string `json:"settlement_status,omitempty" validate:"omitempty,oneof=open partial settled"`
|
||||
// Team is the single-value form of the two filters below, so the team picker can
|
||||
// send back what it was given: a parent category id or "central" for Pusat.
|
||||
Team string `json:"team,omitempty"`
|
||||
TeamScope string `json:"team_scope,omitempty" validate:"omitempty,oneof=category central"`
|
||||
TeamCategoryID *uuid.UUID `json:"team_category_id,omitempty"`
|
||||
StartDate *time.Time `json:"start_date,omitempty"`
|
||||
EndDate *time.Time `json:"end_date,omitempty"`
|
||||
}
|
||||
|
||||
type ListCashAdvancesResponse struct {
|
||||
CashAdvances []CashAdvanceResponse `json:"cash_advances"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
@@ -7,15 +7,18 @@ import (
|
||||
)
|
||||
|
||||
type CreateExpenseRequest struct {
|
||||
Receiver string `json:"receiver" validate:"required"`
|
||||
TransactionDate string `json:"transaction_date" validate:"required"`
|
||||
CodeNumber string `json:"code_number" validate:"required"`
|
||||
OutletID string `json:"outlet_id" validate:"required"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved cancel"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Tax float64 `json:"tax"`
|
||||
Total float64 `json:"total" validate:"required"`
|
||||
Items []CreateExpenseItemRequest `json:"items" validate:"required"`
|
||||
Receiver string `json:"receiver" validate:"required"`
|
||||
TransactionDate string `json:"transaction_date" validate:"required"`
|
||||
CodeNumber string `json:"code_number" validate:"required"`
|
||||
OutletID string `json:"outlet_id" validate:"required"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved cancel"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Tax float64 `json:"tax"`
|
||||
Total float64 `json:"total" validate:"required"`
|
||||
// CashAdvanceID marks the expense as paid out of cash advanced to a team, which is
|
||||
// what accounts for that advance.
|
||||
CashAdvanceID *string `json:"cash_advance_id,omitempty"`
|
||||
Items []CreateExpenseItemRequest `json:"items" validate:"required"`
|
||||
}
|
||||
|
||||
type CreateExpenseItemRequest struct {
|
||||
@@ -27,16 +30,18 @@ type CreateExpenseItemRequest struct {
|
||||
}
|
||||
|
||||
type UpdateExpenseRequest struct {
|
||||
Receiver *string `json:"receiver,omitempty"`
|
||||
TransactionDate *string `json:"transaction_date,omitempty"`
|
||||
CodeNumber *string `json:"code_number,omitempty"`
|
||||
OutletID *string `json:"outlet_id,omitempty"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved cancel"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Tax *float64 `json:"tax,omitempty"`
|
||||
Total *float64 `json:"total,omitempty"`
|
||||
Reserved1 *string `json:"reserved1,omitempty"`
|
||||
Items []UpdateExpenseItemRequest `json:"items,omitempty"`
|
||||
Receiver *string `json:"receiver,omitempty"`
|
||||
TransactionDate *string `json:"transaction_date,omitempty"`
|
||||
CodeNumber *string `json:"code_number,omitempty"`
|
||||
OutletID *string `json:"outlet_id,omitempty"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved cancel"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Tax *float64 `json:"tax,omitempty"`
|
||||
Total *float64 `json:"total,omitempty"`
|
||||
Reserved1 *string `json:"reserved1,omitempty"`
|
||||
// An empty string unlinks the cash advance; omitting the field leaves it untouched.
|
||||
CashAdvanceID *string `json:"cash_advance_id,omitempty"`
|
||||
Items []UpdateExpenseItemRequest `json:"items,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateExpenseItemRequest struct {
|
||||
@@ -59,6 +64,7 @@ type ExpenseResponse struct {
|
||||
Tax float64 `json:"tax"`
|
||||
Total float64 `json:"total"`
|
||||
Reserved1 *string `json:"reserved1,omitempty"`
|
||||
CashAdvanceID *uuid.UUID `json:"cash_advance_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Items []ExpenseItemResponse `json:"items,omitempty"`
|
||||
|
||||
@@ -7,15 +7,18 @@ import (
|
||||
)
|
||||
|
||||
type CreatePurchaseOrderRequest struct {
|
||||
VendorID *uuid.UUID `json:"vendor_id,omitempty" validate:"omitempty"`
|
||||
PONumber string `json:"po_number" validate:"required,min=1,max=50"`
|
||||
TransactionDate string `json:"transaction_date" validate:"required"` // Format: YYYY-MM-DD
|
||||
DueDate *string `json:"due_date,omitempty" validate:"omitempty"` // Format: YYYY-MM-DD
|
||||
Reference *string `json:"reference,omitempty" validate:"omitempty,max=100"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved received cancelled"`
|
||||
Message *string `json:"message,omitempty" validate:"omitempty"`
|
||||
TeamScope *string `json:"team_scope,omitempty" validate:"omitempty,oneof=category central"`
|
||||
TeamCategoryID *uuid.UUID `json:"team_category_id,omitempty" validate:"omitempty"`
|
||||
VendorID *uuid.UUID `json:"vendor_id,omitempty" validate:"omitempty"`
|
||||
PONumber string `json:"po_number" validate:"required,min=1,max=50"`
|
||||
TransactionDate string `json:"transaction_date" validate:"required"` // Format: YYYY-MM-DD
|
||||
DueDate *string `json:"due_date,omitempty" validate:"omitempty"` // Format: YYYY-MM-DD
|
||||
Reference *string `json:"reference,omitempty" validate:"omitempty,max=100"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved received cancelled"`
|
||||
Message *string `json:"message,omitempty" validate:"omitempty"`
|
||||
TeamScope *string `json:"team_scope,omitempty" validate:"omitempty,oneof=category central"`
|
||||
TeamCategoryID *uuid.UUID `json:"team_category_id,omitempty" validate:"omitempty"`
|
||||
// CashAdvanceID marks the purchase as paid out of cash advanced to the team. Sending
|
||||
// it without a team charges the purchase to the cash advance's team.
|
||||
CashAdvanceID *uuid.UUID `json:"cash_advance_id,omitempty" validate:"omitempty"`
|
||||
Items []CreatePurchaseOrderItemRequest `json:"items" validate:"required,min=1,dive"`
|
||||
AttachmentFileIDs []uuid.UUID `json:"attachment_file_ids,omitempty"`
|
||||
}
|
||||
@@ -38,8 +41,10 @@ type UpdatePurchaseOrderRequest struct {
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved received cancelled"`
|
||||
Message *string `json:"message,omitempty" validate:"omitempty"`
|
||||
// An empty string clears the team; omitting the field leaves it untouched.
|
||||
TeamScope *string `json:"team_scope,omitempty" validate:"omitempty"`
|
||||
TeamCategoryID *uuid.UUID `json:"team_category_id,omitempty" validate:"omitempty"`
|
||||
TeamScope *string `json:"team_scope,omitempty" validate:"omitempty"`
|
||||
TeamCategoryID *uuid.UUID `json:"team_category_id,omitempty" validate:"omitempty"`
|
||||
// An all-zero uuid unlinks the cash advance; omitting the field leaves it untouched.
|
||||
CashAdvanceID *uuid.UUID `json:"cash_advance_id,omitempty" validate:"omitempty"`
|
||||
Items []UpdatePurchaseOrderItemRequest `json:"items,omitempty" validate:"omitempty,dive"`
|
||||
AttachmentFileIDs []uuid.UUID `json:"attachment_file_ids,omitempty"`
|
||||
}
|
||||
@@ -68,6 +73,7 @@ type PurchaseOrderResponse struct {
|
||||
TotalAmount float64 `json:"total_amount"`
|
||||
TeamScope *string `json:"team_scope"`
|
||||
TeamCategoryID *uuid.UUID `json:"team_category_id"`
|
||||
CashAdvanceID *uuid.UUID `json:"cash_advance_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Team *PurchaseTeamResponse `json:"team,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user