// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.27.0
// source: sales.sql

package db

import (
	"context"

	"github.com/jackc/pgx/v5/pgtype"
	"github.com/shopspring/decimal"
)

const adjustStock = `-- name: AdjustStock :exec
INSERT INTO stocks (product_id, warehouse_id, quantity, reserved_quantity, last_updated_at)
VALUES ($1,$2,$3,0,now())
ON CONFLICT (product_id, warehouse_id)
DO UPDATE SET quantity = stocks.quantity + $3, last_updated_at = now()
`

type AdjustStockParams struct {
	ProductID   int64           `json:"product_id"`
	WarehouseID int64           `json:"warehouse_id"`
	Quantity    decimal.Decimal `json:"quantity"`
}

func (q *Queries) AdjustStock(ctx context.Context, arg AdjustStockParams) error {
	_, err := q.db.Exec(ctx, adjustStock, arg.ProductID, arg.WarehouseID, arg.Quantity)
	return err
}

const countCustomersActive = `-- name: CountCustomersActive :one
SELECT count(*) FROM customers WHERE id=$1 AND deleted_at IS NULL
`

func (q *Queries) CountCustomersActive(ctx context.Context, id int64) (int64, error) {
	row := q.db.QueryRow(ctx, countCustomersActive, id)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countProductsActive = `-- name: CountProductsActive :one
SELECT count(*) FROM products WHERE id=$1 AND deleted_at IS NULL
`

func (q *Queries) CountProductsActive(ctx context.Context, id int64) (int64, error) {
	row := q.db.QueryRow(ctx, countProductsActive, id)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countSalesOrders = `-- name: CountSalesOrders :one
SELECT count(*) FROM sales_orders
WHERE ($1::text IS NULL OR (so_number ILIKE '%' || $1 || '%' OR customer_id IN (SELECT id FROM customers WHERE name ILIKE '%' || $1 || '%') OR sales_id IN (SELECT id FROM employees WHERE name ILIKE '%' || $1 || '%')))
  AND ($2::text IS NULL OR status = ANY(string_to_array($2, ',')))
  AND ($3::boolean IS NOT TRUE OR status NOT IN ('draft', 'pending_approval', 'blocked_overdue'))
  AND ($4::boolean IS NOT TRUE OR shipping_address IS NULL OR shipping_address !~* '[[]ambil sendiri|[]]ambil di toko|\[ambil sendiri')
  AND ($5::boolean IS NOT TRUE OR shipping_address ~* '[[]ambil sendiri|[]]ambil di toko|\[ambil sendiri')
  AND ($6::bigint IS NULL OR $6::bigint <= 0 OR customer_id = $6)
  AND ($7::text IS NULL OR order_type = $7)
  AND ($8::text IS NULL OR source_type = $8)
  AND ($9::date IS NULL OR order_date >= $9)
  AND ($10::date IS NULL OR order_date <= $10)
  AND ($11::bigint IS NULL OR store_id = $11)
  -- Mirror ListSalesOrders: unbound (e-commerce) orders count for every caller.
  AND ($12::bigint[] IS NULL OR store_id IS NULL OR store_id = ANY($12))
`

type CountSalesOrdersParams struct {
	Search            pgtype.Text `json:"search"`
	Status            pgtype.Text `json:"status"`
	ExcludeUnapproved pgtype.Bool `json:"exclude_unapproved"`
	ExcludePickup     pgtype.Bool `json:"exclude_pickup"`
	PickupOnly        pgtype.Bool `json:"pickup_only"`
	CustomerID        pgtype.Int8 `json:"customer_id"`
	OrderType         pgtype.Text `json:"order_type"`
	SourceType        pgtype.Text `json:"source_type"`
	DateFrom          pgtype.Date `json:"date_from"`
	DateTo            pgtype.Date `json:"date_to"`
	StoreID           pgtype.Int8 `json:"store_id"`
	AllowedStoreIds   []int64     `json:"allowed_store_ids"`
}

// Mirrors ListSalesOrders' search: sales_id resolves through employees only.
func (q *Queries) CountSalesOrders(ctx context.Context, arg CountSalesOrdersParams) (int64, error) {
	row := q.db.QueryRow(ctx, countSalesOrders,
		arg.Search,
		arg.Status,
		arg.ExcludeUnapproved,
		arg.ExcludePickup,
		arg.PickupOnly,
		arg.CustomerID,
		arg.OrderType,
		arg.SourceType,
		arg.DateFrom,
		arg.DateTo,
		arg.StoreID,
		arg.AllowedStoreIds,
	)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countSalesReturns = `-- name: CountSalesReturns :one
SELECT count(*)
FROM sales_returns r
JOIN sales_orders so ON so.id = r.sales_order_id
WHERE ($1::bigint IS NULL OR $1::bigint <= 0 OR r.sales_order_id = $1)
  AND ($2::bigint IS NULL OR $2::bigint <= 0 OR r.customer_id = $2)
  AND ($3::bigint IS NULL OR $3::bigint <= 0 OR so.store_id = $3)
  AND ($4::bigint[] IS NULL OR so.store_id IS NULL OR so.store_id = ANY($4))
`

type CountSalesReturnsParams struct {
	SalesOrderID    pgtype.Int8 `json:"sales_order_id"`
	CustomerID      pgtype.Int8 `json:"customer_id"`
	StoreID         pgtype.Int8 `json:"store_id"`
	AllowedStoreIds []int64     `json:"allowed_store_ids"`
}

func (q *Queries) CountSalesReturns(ctx context.Context, arg CountSalesReturnsParams) (int64, error) {
	row := q.db.QueryRow(ctx, countSalesReturns,
		arg.SalesOrderID,
		arg.CustomerID,
		arg.StoreID,
		arg.AllowedStoreIds,
	)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countSalesVouchers = `-- name: CountSalesVouchers :one
SELECT count(*) FROM sales_vouchers
WHERE ($1::text IS NULL OR status = $1)
  AND ($2::text IS NULL OR type = $2)
  AND ($3::text IS NULL OR voucher_number ILIKE '%' || $3 || '%')
`

type CountSalesVouchersParams struct {
	Status        pgtype.Text `json:"status"`
	Type          pgtype.Text `json:"type"`
	VoucherNumber pgtype.Text `json:"voucher_number"`
}

func (q *Queries) CountSalesVouchers(ctx context.Context, arg CountSalesVouchersParams) (int64, error) {
	row := q.db.QueryRow(ctx, countSalesVouchers, arg.Status, arg.Type, arg.VoucherNumber)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const createCustomerForUser = `-- name: CreateCustomerForUser :one
INSERT INTO customers (code, name, email, user_id, customer_type, is_active, created_at, updated_at)
VALUES ($1,$2,$3,$4,'retail',true,now(),now())
ON CONFLICT (code) DO NOTHING
RETURNING id
`

type CreateCustomerForUserParams struct {
	Code   string      `json:"code"`
	Name   string      `json:"name"`
	Email  pgtype.Text `json:"email"`
	UserID pgtype.Int8 `json:"user_id"`
}

func (q *Queries) CreateCustomerForUser(ctx context.Context, arg CreateCustomerForUserParams) (int64, error) {
	row := q.db.QueryRow(ctx, createCustomerForUser,
		arg.Code,
		arg.Name,
		arg.Email,
		arg.UserID,
	)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const createEcommerceCustomer = `-- name: CreateEcommerceCustomer :one
INSERT INTO customers (code, name, contact_person, phone, email, tax_number, customer_type, user_id, is_active, created_at, updated_at)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,true,now(),now())
ON CONFLICT (code) DO NOTHING
RETURNING id
`

type CreateEcommerceCustomerParams struct {
	Code          string      `json:"code"`
	Name          string      `json:"name"`
	ContactPerson pgtype.Text `json:"contact_person"`
	Phone         pgtype.Text `json:"phone"`
	Email         pgtype.Text `json:"email"`
	TaxNumber     pgtype.Text `json:"tax_number"`
	CustomerType  string      `json:"customer_type"`
	UserID        pgtype.Int8 `json:"user_id"`
}

// Storefront signup: 'retail' for perseorangan, 'wholesale' for bisnis.
func (q *Queries) CreateEcommerceCustomer(ctx context.Context, arg CreateEcommerceCustomerParams) (int64, error) {
	row := q.db.QueryRow(ctx, createEcommerceCustomer,
		arg.Code,
		arg.Name,
		arg.ContactPerson,
		arg.Phone,
		arg.Email,
		arg.TaxNumber,
		arg.CustomerType,
		arg.UserID,
	)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const createSalesCashflow = `-- name: CreateSalesCashflow :one
INSERT INTO cashflows (transaction_number, type, category, transaction_date, amount, description, reference_type, reference_id, created_by)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) RETURNING id
`

type CreateSalesCashflowParams struct {
	TransactionNumber string          `json:"transaction_number"`
	Type              string          `json:"type"`
	Category          string          `json:"category"`
	TransactionDate   pgtype.Date     `json:"transaction_date"`
	Amount            decimal.Decimal `json:"amount"`
	Description       pgtype.Text     `json:"description"`
	ReferenceType     pgtype.Text     `json:"reference_type"`
	ReferenceID       pgtype.Int8     `json:"reference_id"`
	CreatedBy         pgtype.Int8     `json:"created_by"`
}

func (q *Queries) CreateSalesCashflow(ctx context.Context, arg CreateSalesCashflowParams) (int64, error) {
	row := q.db.QueryRow(ctx, createSalesCashflow,
		arg.TransactionNumber,
		arg.Type,
		arg.Category,
		arg.TransactionDate,
		arg.Amount,
		arg.Description,
		arg.ReferenceType,
		arg.ReferenceID,
		arg.CreatedBy,
	)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const createSalesInvoice = `-- name: CreateSalesInvoice :one
INSERT INTO invoices (invoice_number, sales_order_id, customer_id, invoice_date, due_date, status,
       subtotal, tax_amount, total_amount, paid_amount, remaining_amount)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11) RETURNING id
`

type CreateSalesInvoiceParams struct {
	InvoiceNumber   string          `json:"invoice_number"`
	SalesOrderID    pgtype.Int8     `json:"sales_order_id"`
	CustomerID      int64           `json:"customer_id"`
	InvoiceDate     pgtype.Date     `json:"invoice_date"`
	DueDate         pgtype.Date     `json:"due_date"`
	Status          string          `json:"status"`
	Subtotal        decimal.Decimal `json:"subtotal"`
	TaxAmount       decimal.Decimal `json:"tax_amount"`
	TotalAmount     decimal.Decimal `json:"total_amount"`
	PaidAmount      decimal.Decimal `json:"paid_amount"`
	RemainingAmount decimal.Decimal `json:"remaining_amount"`
}

func (q *Queries) CreateSalesInvoice(ctx context.Context, arg CreateSalesInvoiceParams) (int64, error) {
	row := q.db.QueryRow(ctx, createSalesInvoice,
		arg.InvoiceNumber,
		arg.SalesOrderID,
		arg.CustomerID,
		arg.InvoiceDate,
		arg.DueDate,
		arg.Status,
		arg.Subtotal,
		arg.TaxAmount,
		arg.TotalAmount,
		arg.PaidAmount,
		arg.RemainingAmount,
	)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const createSalesOrder = `-- name: CreateSalesOrder :one
INSERT INTO sales_orders (so_number, customer_id, warehouse_id, sales_id, order_date, status, order_type,
       subtotal, tax_amount, discount_amount, total_amount, paid_amount, remaining_amount,
       shipping_cost, shipping_address, notes, delivery_date, store_id, source_type, payment_terms)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20)
RETURNING id, created_at, updated_at
`

type CreateSalesOrderParams struct {
	SoNumber        string          `json:"so_number"`
	CustomerID      int64           `json:"customer_id"`
	WarehouseID     pgtype.Int8     `json:"warehouse_id"`
	SalesID         pgtype.Int8     `json:"sales_id"`
	OrderDate       pgtype.Date     `json:"order_date"`
	Status          string          `json:"status"`
	OrderType       string          `json:"order_type"`
	Subtotal        decimal.Decimal `json:"subtotal"`
	TaxAmount       decimal.Decimal `json:"tax_amount"`
	DiscountAmount  decimal.Decimal `json:"discount_amount"`
	TotalAmount     decimal.Decimal `json:"total_amount"`
	PaidAmount      decimal.Decimal `json:"paid_amount"`
	RemainingAmount decimal.Decimal `json:"remaining_amount"`
	ShippingCost    decimal.Decimal `json:"shipping_cost"`
	ShippingAddress pgtype.Text     `json:"shipping_address"`
	Notes           pgtype.Text     `json:"notes"`
	DeliveryDate    pgtype.Date     `json:"delivery_date"`
	StoreID         pgtype.Int8     `json:"store_id"`
	SourceType      pgtype.Text     `json:"source_type"`
	PaymentTerms    int32           `json:"payment_terms"`
}

type CreateSalesOrderRow struct {
	ID        int64              `json:"id"`
	CreatedAt pgtype.Timestamptz `json:"created_at"`
	UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}

func (q *Queries) CreateSalesOrder(ctx context.Context, arg CreateSalesOrderParams) (CreateSalesOrderRow, error) {
	row := q.db.QueryRow(ctx, createSalesOrder,
		arg.SoNumber,
		arg.CustomerID,
		arg.WarehouseID,
		arg.SalesID,
		arg.OrderDate,
		arg.Status,
		arg.OrderType,
		arg.Subtotal,
		arg.TaxAmount,
		arg.DiscountAmount,
		arg.TotalAmount,
		arg.PaidAmount,
		arg.RemainingAmount,
		arg.ShippingCost,
		arg.ShippingAddress,
		arg.Notes,
		arg.DeliveryDate,
		arg.StoreID,
		arg.SourceType,
		arg.PaymentTerms,
	)
	var i CreateSalesOrderRow
	err := row.Scan(&i.ID, &i.CreatedAt, &i.UpdatedAt)
	return i, err
}

const createSalesOrderItem = `-- name: CreateSalesOrderItem :one
INSERT INTO sales_order_items (sales_order_id, product_id, quantity, unit_price, discount_percent, discount_amount, subtotal,
       product_unit_id, unit_id, unit_name, unit_symbol, conversion_factor, base_quantity, min_purchase,
       membership_tier, membership_discount_amount)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16) RETURNING id
`

type CreateSalesOrderItemParams struct {
	SalesOrderID             int64           `json:"sales_order_id"`
	ProductID                int64           `json:"product_id"`
	Quantity                 decimal.Decimal `json:"quantity"`
	UnitPrice                decimal.Decimal `json:"unit_price"`
	DiscountPercent          decimal.Decimal `json:"discount_percent"`
	DiscountAmount           decimal.Decimal `json:"discount_amount"`
	Subtotal                 decimal.Decimal `json:"subtotal"`
	ProductUnitID            pgtype.Int8     `json:"product_unit_id"`
	UnitID                   pgtype.Int8     `json:"unit_id"`
	UnitName                 string          `json:"unit_name"`
	UnitSymbol               string          `json:"unit_symbol"`
	ConversionFactor         decimal.Decimal `json:"conversion_factor"`
	BaseQuantity             decimal.Decimal `json:"base_quantity"`
	MinPurchase              decimal.Decimal `json:"min_purchase"`
	MembershipTier           string          `json:"membership_tier"`
	MembershipDiscountAmount decimal.Decimal `json:"membership_discount_amount"`
}

func (q *Queries) CreateSalesOrderItem(ctx context.Context, arg CreateSalesOrderItemParams) (int64, error) {
	row := q.db.QueryRow(ctx, createSalesOrderItem,
		arg.SalesOrderID,
		arg.ProductID,
		arg.Quantity,
		arg.UnitPrice,
		arg.DiscountPercent,
		arg.DiscountAmount,
		arg.Subtotal,
		arg.ProductUnitID,
		arg.UnitID,
		arg.UnitName,
		arg.UnitSymbol,
		arg.ConversionFactor,
		arg.BaseQuantity,
		arg.MinPurchase,
		arg.MembershipTier,
		arg.MembershipDiscountAmount,
	)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const createSalesPayment = `-- name: CreateSalesPayment :one
INSERT INTO payments (payment_number, payable_type, payable_id, payment_date, amount, payment_method, notes, created_by)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING id
`

type CreateSalesPaymentParams struct {
	PaymentNumber string          `json:"payment_number"`
	PayableType   string          `json:"payable_type"`
	PayableID     int64           `json:"payable_id"`
	PaymentDate   pgtype.Date     `json:"payment_date"`
	Amount        decimal.Decimal `json:"amount"`
	PaymentMethod string          `json:"payment_method"`
	Notes         pgtype.Text     `json:"notes"`
	CreatedBy     pgtype.Int8     `json:"created_by"`
}

func (q *Queries) CreateSalesPayment(ctx context.Context, arg CreateSalesPaymentParams) (int64, error) {
	row := q.db.QueryRow(ctx, createSalesPayment,
		arg.PaymentNumber,
		arg.PayableType,
		arg.PayableID,
		arg.PaymentDate,
		arg.Amount,
		arg.PaymentMethod,
		arg.Notes,
		arg.CreatedBy,
	)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const createSalesReturn = `-- name: CreateSalesReturn :one
INSERT INTO sales_returns (return_number, sales_order_id, customer_id, warehouse_id, return_date,
       refund_amount, refund_method, status, reason, created_by)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)
RETURNING id, return_number, sales_order_id, customer_id, warehouse_id, return_date::text AS return_date,
          refund_amount, refund_method, status, reason, created_by, created_at, updated_at
`

type CreateSalesReturnParams struct {
	ReturnNumber string          `json:"return_number"`
	SalesOrderID int64           `json:"sales_order_id"`
	CustomerID   int64           `json:"customer_id"`
	WarehouseID  pgtype.Int8     `json:"warehouse_id"`
	ReturnDate   pgtype.Date     `json:"return_date"`
	RefundAmount decimal.Decimal `json:"refund_amount"`
	RefundMethod string          `json:"refund_method"`
	Status       string          `json:"status"`
	Reason       pgtype.Text     `json:"reason"`
	CreatedBy    pgtype.Int8     `json:"created_by"`
}

type CreateSalesReturnRow struct {
	ID           int64              `json:"id"`
	ReturnNumber string             `json:"return_number"`
	SalesOrderID int64              `json:"sales_order_id"`
	CustomerID   int64              `json:"customer_id"`
	WarehouseID  pgtype.Int8        `json:"warehouse_id"`
	ReturnDate   string             `json:"return_date"`
	RefundAmount decimal.Decimal    `json:"refund_amount"`
	RefundMethod string             `json:"refund_method"`
	Status       string             `json:"status"`
	Reason       pgtype.Text        `json:"reason"`
	CreatedBy    pgtype.Int8        `json:"created_by"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
}

func (q *Queries) CreateSalesReturn(ctx context.Context, arg CreateSalesReturnParams) (CreateSalesReturnRow, error) {
	row := q.db.QueryRow(ctx, createSalesReturn,
		arg.ReturnNumber,
		arg.SalesOrderID,
		arg.CustomerID,
		arg.WarehouseID,
		arg.ReturnDate,
		arg.RefundAmount,
		arg.RefundMethod,
		arg.Status,
		arg.Reason,
		arg.CreatedBy,
	)
	var i CreateSalesReturnRow
	err := row.Scan(
		&i.ID,
		&i.ReturnNumber,
		&i.SalesOrderID,
		&i.CustomerID,
		&i.WarehouseID,
		&i.ReturnDate,
		&i.RefundAmount,
		&i.RefundMethod,
		&i.Status,
		&i.Reason,
		&i.CreatedBy,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const createSalesReturnItem = `-- name: CreateSalesReturnItem :one
INSERT INTO sales_return_items (sales_return_id, sales_order_item_id, product_id, quantity, unit_price, refund_amount, reason)
VALUES ($1,$2,$3,$4,$5,$6,$7)
RETURNING id, sales_return_id, sales_order_item_id, product_id, quantity, unit_price, refund_amount, reason, condition, restocked, created_at
`

type CreateSalesReturnItemParams struct {
	SalesReturnID    int64           `json:"sales_return_id"`
	SalesOrderItemID int64           `json:"sales_order_item_id"`
	ProductID        int64           `json:"product_id"`
	Quantity         decimal.Decimal `json:"quantity"`
	UnitPrice        decimal.Decimal `json:"unit_price"`
	RefundAmount     decimal.Decimal `json:"refund_amount"`
	Reason           pgtype.Text     `json:"reason"`
}

func (q *Queries) CreateSalesReturnItem(ctx context.Context, arg CreateSalesReturnItemParams) (SalesReturnItem, error) {
	row := q.db.QueryRow(ctx, createSalesReturnItem,
		arg.SalesReturnID,
		arg.SalesOrderItemID,
		arg.ProductID,
		arg.Quantity,
		arg.UnitPrice,
		arg.RefundAmount,
		arg.Reason,
	)
	var i SalesReturnItem
	err := row.Scan(
		&i.ID,
		&i.SalesReturnID,
		&i.SalesOrderItemID,
		&i.ProductID,
		&i.Quantity,
		&i.UnitPrice,
		&i.RefundAmount,
		&i.Reason,
		&i.Condition,
		&i.Restocked,
		&i.CreatedAt,
	)
	return i, err
}

const createSalesVoucher = `-- name: CreateSalesVoucher :one

INSERT INTO sales_vouchers (voucher_number, type, description, voucher_date, amount, status, created_by, expired_at)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8)
RETURNING id, voucher_number, type, description, voucher_date::text AS voucher_date, amount, status, created_by, created_at, updated_at, expired_at
`

type CreateSalesVoucherParams struct {
	VoucherNumber string          `json:"voucher_number"`
	Type          string          `json:"type"`
	Description   pgtype.Text     `json:"description"`
	VoucherDate   pgtype.Date     `json:"voucher_date"`
	Amount        decimal.Decimal `json:"amount"`
	Status        string          `json:"status"`
	CreatedBy     pgtype.Int8     `json:"created_by"`
	ExpiredAt     pgtype.Date     `json:"expired_at"`
}

type CreateSalesVoucherRow struct {
	ID            int64              `json:"id"`
	VoucherNumber string             `json:"voucher_number"`
	Type          string             `json:"type"`
	Description   pgtype.Text        `json:"description"`
	VoucherDate   string             `json:"voucher_date"`
	Amount        decimal.Decimal    `json:"amount"`
	Status        string             `json:"status"`
	CreatedBy     pgtype.Int8        `json:"created_by"`
	CreatedAt     pgtype.Timestamptz `json:"created_at"`
	UpdatedAt     pgtype.Timestamptz `json:"updated_at"`
	ExpiredAt     pgtype.Date        `json:"expired_at"`
}

// Sales Voucher queries (Phase 6 Item 4)
func (q *Queries) CreateSalesVoucher(ctx context.Context, arg CreateSalesVoucherParams) (CreateSalesVoucherRow, error) {
	row := q.db.QueryRow(ctx, createSalesVoucher,
		arg.VoucherNumber,
		arg.Type,
		arg.Description,
		arg.VoucherDate,
		arg.Amount,
		arg.Status,
		arg.CreatedBy,
		arg.ExpiredAt,
	)
	var i CreateSalesVoucherRow
	err := row.Scan(
		&i.ID,
		&i.VoucherNumber,
		&i.Type,
		&i.Description,
		&i.VoucherDate,
		&i.Amount,
		&i.Status,
		&i.CreatedBy,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.ExpiredAt,
	)
	return i, err
}

const deleteSalesOrder = `-- name: DeleteSalesOrder :execrows
DELETE FROM sales_orders WHERE id=$1
`

func (q *Queries) DeleteSalesOrder(ctx context.Context, id int64) (int64, error) {
	result, err := q.db.Exec(ctx, deleteSalesOrder, id)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const deleteSalesOrderItems = `-- name: DeleteSalesOrderItems :exec
DELETE FROM sales_order_items WHERE sales_order_id=$1
`

func (q *Queries) DeleteSalesOrderItems(ctx context.Context, salesOrderID int64) error {
	_, err := q.db.Exec(ctx, deleteSalesOrderItems, salesOrderID)
	return err
}

const ensureSalesStockRow = `-- name: EnsureSalesStockRow :exec
INSERT INTO stocks (product_id, warehouse_id, quantity, reserved_quantity, last_updated_at)
VALUES ($1, $2, 0, 0, now())
ON CONFLICT (product_id, warehouse_id) DO NOTHING
`

type EnsureSalesStockRowParams struct {
	ProductID   int64 `json:"product_id"`
	WarehouseID int64 `json:"warehouse_id"`
}

func (q *Queries) EnsureSalesStockRow(ctx context.Context, arg EnsureSalesStockRowParams) error {
	_, err := q.db.Exec(ctx, ensureSalesStockRow, arg.ProductID, arg.WarehouseID)
	return err
}

const firstActiveStore = `-- name: FirstActiveStore :one
SELECT id, warehouse_id FROM stores WHERE is_active = true ORDER BY id LIMIT 1
`

type FirstActiveStoreRow struct {
	ID          int64 `json:"id"`
	WarehouseID int64 `json:"warehouse_id"`
}

func (q *Queries) FirstActiveStore(ctx context.Context) (FirstActiveStoreRow, error) {
	row := q.db.QueryRow(ctx, firstActiveStore)
	var i FirstActiveStoreRow
	err := row.Scan(&i.ID, &i.WarehouseID)
	return i, err
}

const firstActiveWarehouse = `-- name: FirstActiveWarehouse :one
SELECT id FROM warehouses WHERE is_active = true ORDER BY id LIMIT 1
`

func (q *Queries) FirstActiveWarehouse(ctx context.Context) (int64, error) {
	row := q.db.QueryRow(ctx, firstActiveWarehouse)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const getCustomerAssignedSales = `-- name: GetCustomerAssignedSales :one
SELECT assigned_sales_id FROM customers WHERE id=$1 AND deleted_at IS NULL
`

// Referral attribution: sales user linked to a customer (nullable).
func (q *Queries) GetCustomerAssignedSales(ctx context.Context, id int64) (pgtype.Int8, error) {
	row := q.db.QueryRow(ctx, getCustomerAssignedSales, id)
	var assigned_sales_id pgtype.Int8
	err := row.Scan(&assigned_sales_id)
	return assigned_sales_id, err
}

const getCustomerIDByUserID = `-- name: GetCustomerIDByUserID :one
SELECT id FROM customers WHERE user_id=$1 AND deleted_at IS NULL
`

func (q *Queries) GetCustomerIDByUserID(ctx context.Context, userID pgtype.Int8) (int64, error) {
	row := q.db.QueryRow(ctx, getCustomerIDByUserID, userID)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const getProductSellingPrice = `-- name: GetProductSellingPrice :one
SELECT selling_price FROM products WHERE id=$1 AND deleted_at IS NULL
`

func (q *Queries) GetProductSellingPrice(ctx context.Context, id int64) (decimal.Decimal, error) {
	row := q.db.QueryRow(ctx, getProductSellingPrice, id)
	var selling_price decimal.Decimal
	err := row.Scan(&selling_price)
	return selling_price, err
}

const getSalesOrderByID = `-- name: GetSalesOrderByID :one
SELECT o.id, o.so_number, o.customer_id, o.warehouse_id, o.sales_id, o.store_id, o.order_date::text AS order_date, o.status, o.order_type, o.source_type,
       o.subtotal, o.tax_amount, o.discount_amount, o.total_amount, o.paid_amount, o.remaining_amount,
       o.shipping_cost, o.shipping_address, o.notes, o.received_proof_url, o.delivery_date, o.created_at, o.updated_at,
       c.name AS customer_name, se.name AS sales_name, w.name AS warehouse_name,
       o.payment_terms,
       COALESCE((SELECT p.payment_method FROM payments p JOIN invoices i ON i.id = p.payable_id WHERE (p.payable_type = 'App\Models\Invoice' OR p.payable_type = 'invoice') AND i.sales_order_id = o.id ORDER BY p.id DESC LIMIT 1), '')::text AS payment_method
FROM sales_orders o
LEFT JOIN customers c ON c.id = o.customer_id
LEFT JOIN employees se ON se.id = o.sales_id
LEFT JOIN warehouses w ON w.id = o.warehouse_id
WHERE o.id=$1
`

type GetSalesOrderByIDRow struct {
	ID               int64              `json:"id"`
	SoNumber         string             `json:"so_number"`
	CustomerID       int64              `json:"customer_id"`
	WarehouseID      pgtype.Int8        `json:"warehouse_id"`
	SalesID          pgtype.Int8        `json:"sales_id"`
	StoreID          pgtype.Int8        `json:"store_id"`
	OrderDate        string             `json:"order_date"`
	Status           string             `json:"status"`
	OrderType        string             `json:"order_type"`
	SourceType       pgtype.Text        `json:"source_type"`
	Subtotal         decimal.Decimal    `json:"subtotal"`
	TaxAmount        decimal.Decimal    `json:"tax_amount"`
	DiscountAmount   decimal.Decimal    `json:"discount_amount"`
	TotalAmount      decimal.Decimal    `json:"total_amount"`
	PaidAmount       decimal.Decimal    `json:"paid_amount"`
	RemainingAmount  decimal.Decimal    `json:"remaining_amount"`
	ShippingCost     decimal.Decimal    `json:"shipping_cost"`
	ShippingAddress  pgtype.Text        `json:"shipping_address"`
	Notes            pgtype.Text        `json:"notes"`
	ReceivedProofUrl pgtype.Text        `json:"received_proof_url"`
	DeliveryDate     pgtype.Date        `json:"delivery_date"`
	CreatedAt        pgtype.Timestamptz `json:"created_at"`
	UpdatedAt        pgtype.Timestamptz `json:"updated_at"`
	CustomerName     pgtype.Text        `json:"customer_name"`
	SalesName        pgtype.Text        `json:"sales_name"`
	WarehouseName    pgtype.Text        `json:"warehouse_name"`
	PaymentTerms     int32              `json:"payment_terms"`
	PaymentMethod    string             `json:"payment_method"`
}

// sales_name resolves through employees ONLY. sales_id FKs employees(id)
// (000001_init_schema.sql:235), so the employee is the row the id actually
// points at. See the migration that remapped the legacy users.id values.
func (q *Queries) GetSalesOrderByID(ctx context.Context, id int64) (GetSalesOrderByIDRow, error) {
	row := q.db.QueryRow(ctx, getSalesOrderByID, id)
	var i GetSalesOrderByIDRow
	err := row.Scan(
		&i.ID,
		&i.SoNumber,
		&i.CustomerID,
		&i.WarehouseID,
		&i.SalesID,
		&i.StoreID,
		&i.OrderDate,
		&i.Status,
		&i.OrderType,
		&i.SourceType,
		&i.Subtotal,
		&i.TaxAmount,
		&i.DiscountAmount,
		&i.TotalAmount,
		&i.PaidAmount,
		&i.RemainingAmount,
		&i.ShippingCost,
		&i.ShippingAddress,
		&i.Notes,
		&i.ReceivedProofUrl,
		&i.DeliveryDate,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.CustomerName,
		&i.SalesName,
		&i.WarehouseName,
		&i.PaymentTerms,
		&i.PaymentMethod,
	)
	return i, err
}

const getSalesOrderByIDForUpdate = `-- name: GetSalesOrderByIDForUpdate :one
SELECT o.id, o.so_number, o.customer_id, o.warehouse_id, o.sales_id, o.store_id, o.order_date::text AS order_date, o.status, o.order_type, o.source_type,
       o.subtotal, o.tax_amount, o.discount_amount, o.total_amount, o.paid_amount, o.remaining_amount,
       o.shipping_cost, o.shipping_address, o.notes, o.received_proof_url, o.delivery_date, o.created_at, o.updated_at,
       c.name AS customer_name, se.name AS sales_name, w.name AS warehouse_name,
       o.payment_terms,
       COALESCE((SELECT p.payment_method FROM payments p JOIN invoices i ON i.id = p.payable_id WHERE (p.payable_type = 'App\Models\Invoice' OR p.payable_type = 'invoice') AND i.sales_order_id = o.id ORDER BY p.id DESC LIMIT 1), '')::text AS payment_method
FROM sales_orders o
LEFT JOIN customers c ON c.id = o.customer_id
LEFT JOIN employees se ON se.id = o.sales_id
LEFT JOIN warehouses w ON w.id = o.warehouse_id
WHERE o.id=$1 FOR UPDATE OF o
`

type GetSalesOrderByIDForUpdateRow struct {
	ID               int64              `json:"id"`
	SoNumber         string             `json:"so_number"`
	CustomerID       int64              `json:"customer_id"`
	WarehouseID      pgtype.Int8        `json:"warehouse_id"`
	SalesID          pgtype.Int8        `json:"sales_id"`
	StoreID          pgtype.Int8        `json:"store_id"`
	OrderDate        string             `json:"order_date"`
	Status           string             `json:"status"`
	OrderType        string             `json:"order_type"`
	SourceType       pgtype.Text        `json:"source_type"`
	Subtotal         decimal.Decimal    `json:"subtotal"`
	TaxAmount        decimal.Decimal    `json:"tax_amount"`
	DiscountAmount   decimal.Decimal    `json:"discount_amount"`
	TotalAmount      decimal.Decimal    `json:"total_amount"`
	PaidAmount       decimal.Decimal    `json:"paid_amount"`
	RemainingAmount  decimal.Decimal    `json:"remaining_amount"`
	ShippingCost     decimal.Decimal    `json:"shipping_cost"`
	ShippingAddress  pgtype.Text        `json:"shipping_address"`
	Notes            pgtype.Text        `json:"notes"`
	ReceivedProofUrl pgtype.Text        `json:"received_proof_url"`
	DeliveryDate     pgtype.Date        `json:"delivery_date"`
	CreatedAt        pgtype.Timestamptz `json:"created_at"`
	UpdatedAt        pgtype.Timestamptz `json:"updated_at"`
	CustomerName     pgtype.Text        `json:"customer_name"`
	SalesName        pgtype.Text        `json:"sales_name"`
	WarehouseName    pgtype.Text        `json:"warehouse_name"`
	PaymentTerms     int32              `json:"payment_terms"`
	PaymentMethod    string             `json:"payment_method"`
}

// Same employees-only resolution as GetSalesOrderByID; FOR UPDATE OF o keeps
// the lock on the order row, not on the joined lookup tables.
func (q *Queries) GetSalesOrderByIDForUpdate(ctx context.Context, id int64) (GetSalesOrderByIDForUpdateRow, error) {
	row := q.db.QueryRow(ctx, getSalesOrderByIDForUpdate, id)
	var i GetSalesOrderByIDForUpdateRow
	err := row.Scan(
		&i.ID,
		&i.SoNumber,
		&i.CustomerID,
		&i.WarehouseID,
		&i.SalesID,
		&i.StoreID,
		&i.OrderDate,
		&i.Status,
		&i.OrderType,
		&i.SourceType,
		&i.Subtotal,
		&i.TaxAmount,
		&i.DiscountAmount,
		&i.TotalAmount,
		&i.PaidAmount,
		&i.RemainingAmount,
		&i.ShippingCost,
		&i.ShippingAddress,
		&i.Notes,
		&i.ReceivedProofUrl,
		&i.DeliveryDate,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.CustomerName,
		&i.SalesName,
		&i.WarehouseName,
		&i.PaymentTerms,
		&i.PaymentMethod,
	)
	return i, err
}

const getSalesOrderShiftID = `-- name: GetSalesOrderShiftID :one
SELECT shift_id FROM sales_orders WHERE id=$1
`

func (q *Queries) GetSalesOrderShiftID(ctx context.Context, id int64) (pgtype.Int8, error) {
	row := q.db.QueryRow(ctx, getSalesOrderShiftID, id)
	var shift_id pgtype.Int8
	err := row.Scan(&shift_id)
	return shift_id, err
}

const getSalesReturnByID = `-- name: GetSalesReturnByID :one
SELECT r.id, r.return_number, r.sales_order_id, r.customer_id, r.warehouse_id, r.return_date::text AS return_date,
       r.refund_amount, r.refund_method, r.status, r.reason, r.created_by, r.created_at, r.updated_at,
       so.so_number, c.name AS customer_name
FROM sales_returns r
JOIN sales_orders so ON so.id = r.sales_order_id
JOIN customers c ON c.id = r.customer_id
WHERE r.id=$1
`

type GetSalesReturnByIDRow struct {
	ID           int64              `json:"id"`
	ReturnNumber string             `json:"return_number"`
	SalesOrderID int64              `json:"sales_order_id"`
	CustomerID   int64              `json:"customer_id"`
	WarehouseID  pgtype.Int8        `json:"warehouse_id"`
	ReturnDate   string             `json:"return_date"`
	RefundAmount decimal.Decimal    `json:"refund_amount"`
	RefundMethod string             `json:"refund_method"`
	Status       string             `json:"status"`
	Reason       pgtype.Text        `json:"reason"`
	CreatedBy    pgtype.Int8        `json:"created_by"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	SoNumber     string             `json:"so_number"`
	CustomerName string             `json:"customer_name"`
}

func (q *Queries) GetSalesReturnByID(ctx context.Context, id int64) (GetSalesReturnByIDRow, error) {
	row := q.db.QueryRow(ctx, getSalesReturnByID, id)
	var i GetSalesReturnByIDRow
	err := row.Scan(
		&i.ID,
		&i.ReturnNumber,
		&i.SalesOrderID,
		&i.CustomerID,
		&i.WarehouseID,
		&i.ReturnDate,
		&i.RefundAmount,
		&i.RefundMethod,
		&i.Status,
		&i.Reason,
		&i.CreatedBy,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.SoNumber,
		&i.CustomerName,
	)
	return i, err
}

const getSalesStockRow = `-- name: GetSalesStockRow :one
SELECT id, product_id, warehouse_id, quantity, reserved_quantity, created_at, updated_at
FROM stocks WHERE product_id=$1 AND warehouse_id=$2
`

type GetSalesStockRowParams struct {
	ProductID   int64 `json:"product_id"`
	WarehouseID int64 `json:"warehouse_id"`
}

type GetSalesStockRowRow struct {
	ID               int64              `json:"id"`
	ProductID        int64              `json:"product_id"`
	WarehouseID      int64              `json:"warehouse_id"`
	Quantity         decimal.Decimal    `json:"quantity"`
	ReservedQuantity decimal.Decimal    `json:"reserved_quantity"`
	CreatedAt        pgtype.Timestamptz `json:"created_at"`
	UpdatedAt        pgtype.Timestamptz `json:"updated_at"`
}

func (q *Queries) GetSalesStockRow(ctx context.Context, arg GetSalesStockRowParams) (GetSalesStockRowRow, error) {
	row := q.db.QueryRow(ctx, getSalesStockRow, arg.ProductID, arg.WarehouseID)
	var i GetSalesStockRowRow
	err := row.Scan(
		&i.ID,
		&i.ProductID,
		&i.WarehouseID,
		&i.Quantity,
		&i.ReservedQuantity,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const getSalesStockRowForUpdate = `-- name: GetSalesStockRowForUpdate :one
SELECT id, product_id, warehouse_id, quantity, reserved_quantity, created_at, updated_at
FROM stocks WHERE product_id=$1 AND warehouse_id=$2 FOR UPDATE
`

type GetSalesStockRowForUpdateParams struct {
	ProductID   int64 `json:"product_id"`
	WarehouseID int64 `json:"warehouse_id"`
}

type GetSalesStockRowForUpdateRow struct {
	ID               int64              `json:"id"`
	ProductID        int64              `json:"product_id"`
	WarehouseID      int64              `json:"warehouse_id"`
	Quantity         decimal.Decimal    `json:"quantity"`
	ReservedQuantity decimal.Decimal    `json:"reserved_quantity"`
	CreatedAt        pgtype.Timestamptz `json:"created_at"`
	UpdatedAt        pgtype.Timestamptz `json:"updated_at"`
}

func (q *Queries) GetSalesStockRowForUpdate(ctx context.Context, arg GetSalesStockRowForUpdateParams) (GetSalesStockRowForUpdateRow, error) {
	row := q.db.QueryRow(ctx, getSalesStockRowForUpdate, arg.ProductID, arg.WarehouseID)
	var i GetSalesStockRowForUpdateRow
	err := row.Scan(
		&i.ID,
		&i.ProductID,
		&i.WarehouseID,
		&i.Quantity,
		&i.ReservedQuantity,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const getSalesVoucherByID = `-- name: GetSalesVoucherByID :one
SELECT id, voucher_number, type, description, voucher_date::text AS voucher_date, amount, status, created_by, created_at, updated_at, expired_at
FROM sales_vouchers WHERE id=$1
`

type GetSalesVoucherByIDRow struct {
	ID            int64              `json:"id"`
	VoucherNumber string             `json:"voucher_number"`
	Type          string             `json:"type"`
	Description   pgtype.Text        `json:"description"`
	VoucherDate   string             `json:"voucher_date"`
	Amount        decimal.Decimal    `json:"amount"`
	Status        string             `json:"status"`
	CreatedBy     pgtype.Int8        `json:"created_by"`
	CreatedAt     pgtype.Timestamptz `json:"created_at"`
	UpdatedAt     pgtype.Timestamptz `json:"updated_at"`
	ExpiredAt     pgtype.Date        `json:"expired_at"`
}

func (q *Queries) GetSalesVoucherByID(ctx context.Context, id int64) (GetSalesVoucherByIDRow, error) {
	row := q.db.QueryRow(ctx, getSalesVoucherByID, id)
	var i GetSalesVoucherByIDRow
	err := row.Scan(
		&i.ID,
		&i.VoucherNumber,
		&i.Type,
		&i.Description,
		&i.VoucherDate,
		&i.Amount,
		&i.Status,
		&i.CreatedBy,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.ExpiredAt,
	)
	return i, err
}

const getSalesVoucherByIDForUpdate = `-- name: GetSalesVoucherByIDForUpdate :one
SELECT id, voucher_number, type, description, voucher_date::text AS voucher_date, amount, status, created_by, created_at, updated_at, expired_at
FROM sales_vouchers WHERE id=$1 FOR UPDATE
`

type GetSalesVoucherByIDForUpdateRow struct {
	ID            int64              `json:"id"`
	VoucherNumber string             `json:"voucher_number"`
	Type          string             `json:"type"`
	Description   pgtype.Text        `json:"description"`
	VoucherDate   string             `json:"voucher_date"`
	Amount        decimal.Decimal    `json:"amount"`
	Status        string             `json:"status"`
	CreatedBy     pgtype.Int8        `json:"created_by"`
	CreatedAt     pgtype.Timestamptz `json:"created_at"`
	UpdatedAt     pgtype.Timestamptz `json:"updated_at"`
	ExpiredAt     pgtype.Date        `json:"expired_at"`
}

func (q *Queries) GetSalesVoucherByIDForUpdate(ctx context.Context, id int64) (GetSalesVoucherByIDForUpdateRow, error) {
	row := q.db.QueryRow(ctx, getSalesVoucherByIDForUpdate, id)
	var i GetSalesVoucherByIDForUpdateRow
	err := row.Scan(
		&i.ID,
		&i.VoucherNumber,
		&i.Type,
		&i.Description,
		&i.VoucherDate,
		&i.Amount,
		&i.Status,
		&i.CreatedBy,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.ExpiredAt,
	)
	return i, err
}

const getSalesVoucherByNumber = `-- name: GetSalesVoucherByNumber :one
SELECT id, voucher_number, type, description, voucher_date::text AS voucher_date, amount, status, created_by, created_at, updated_at, expired_at
FROM sales_vouchers WHERE voucher_number=$1
`

type GetSalesVoucherByNumberRow struct {
	ID            int64              `json:"id"`
	VoucherNumber string             `json:"voucher_number"`
	Type          string             `json:"type"`
	Description   pgtype.Text        `json:"description"`
	VoucherDate   string             `json:"voucher_date"`
	Amount        decimal.Decimal    `json:"amount"`
	Status        string             `json:"status"`
	CreatedBy     pgtype.Int8        `json:"created_by"`
	CreatedAt     pgtype.Timestamptz `json:"created_at"`
	UpdatedAt     pgtype.Timestamptz `json:"updated_at"`
	ExpiredAt     pgtype.Date        `json:"expired_at"`
}

func (q *Queries) GetSalesVoucherByNumber(ctx context.Context, voucherNumber string) (GetSalesVoucherByNumberRow, error) {
	row := q.db.QueryRow(ctx, getSalesVoucherByNumber, voucherNumber)
	var i GetSalesVoucherByNumberRow
	err := row.Scan(
		&i.ID,
		&i.VoucherNumber,
		&i.Type,
		&i.Description,
		&i.VoucherDate,
		&i.Amount,
		&i.Status,
		&i.CreatedBy,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.ExpiredAt,
	)
	return i, err
}

const getSalesVoucherByNumberForUpdate = `-- name: GetSalesVoucherByNumberForUpdate :one
SELECT id, voucher_number, type, description, voucher_date::text AS voucher_date, amount, status, created_by, created_at, updated_at, expired_at
FROM sales_vouchers WHERE voucher_number=$1 FOR UPDATE
`

type GetSalesVoucherByNumberForUpdateRow struct {
	ID            int64              `json:"id"`
	VoucherNumber string             `json:"voucher_number"`
	Type          string             `json:"type"`
	Description   pgtype.Text        `json:"description"`
	VoucherDate   string             `json:"voucher_date"`
	Amount        decimal.Decimal    `json:"amount"`
	Status        string             `json:"status"`
	CreatedBy     pgtype.Int8        `json:"created_by"`
	CreatedAt     pgtype.Timestamptz `json:"created_at"`
	UpdatedAt     pgtype.Timestamptz `json:"updated_at"`
	ExpiredAt     pgtype.Date        `json:"expired_at"`
}

func (q *Queries) GetSalesVoucherByNumberForUpdate(ctx context.Context, voucherNumber string) (GetSalesVoucherByNumberForUpdateRow, error) {
	row := q.db.QueryRow(ctx, getSalesVoucherByNumberForUpdate, voucherNumber)
	var i GetSalesVoucherByNumberForUpdateRow
	err := row.Scan(
		&i.ID,
		&i.VoucherNumber,
		&i.Type,
		&i.Description,
		&i.VoucherDate,
		&i.Amount,
		&i.Status,
		&i.CreatedBy,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.ExpiredAt,
	)
	return i, err
}

const getWalkInCustomerID = `-- name: GetWalkInCustomerID :one
SELECT id FROM customers WHERE code='CUS-000' AND deleted_at IS NULL LIMIT 1
`

func (q *Queries) GetWalkInCustomerID(ctx context.Context) (int64, error) {
	row := q.db.QueryRow(ctx, getWalkInCustomerID)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const listSalesOrderItems = `-- name: ListSalesOrderItems :many
SELECT i.id, i.sales_order_id, i.product_id, i.quantity, i.unit_price, i.discount_percent,
       i.discount_amount, i.subtotal, i.product_unit_id, i.unit_id, i.unit_name, i.unit_symbol,
       i.conversion_factor, i.base_quantity, i.min_purchase, p.code, p.name,
       i.membership_tier, i.membership_discount_amount
FROM sales_order_items i
JOIN products p ON p.id = i.product_id
WHERE i.sales_order_id=$1 ORDER BY i.id
`

type ListSalesOrderItemsRow struct {
	ID                       int64           `json:"id"`
	SalesOrderID             int64           `json:"sales_order_id"`
	ProductID                int64           `json:"product_id"`
	Quantity                 decimal.Decimal `json:"quantity"`
	UnitPrice                decimal.Decimal `json:"unit_price"`
	DiscountPercent          decimal.Decimal `json:"discount_percent"`
	DiscountAmount           decimal.Decimal `json:"discount_amount"`
	Subtotal                 decimal.Decimal `json:"subtotal"`
	ProductUnitID            pgtype.Int8     `json:"product_unit_id"`
	UnitID                   pgtype.Int8     `json:"unit_id"`
	UnitName                 string          `json:"unit_name"`
	UnitSymbol               string          `json:"unit_symbol"`
	ConversionFactor         decimal.Decimal `json:"conversion_factor"`
	BaseQuantity             decimal.Decimal `json:"base_quantity"`
	MinPurchase              decimal.Decimal `json:"min_purchase"`
	Code                     string          `json:"code"`
	Name                     string          `json:"name"`
	MembershipTier           string          `json:"membership_tier"`
	MembershipDiscountAmount decimal.Decimal `json:"membership_discount_amount"`
}

func (q *Queries) ListSalesOrderItems(ctx context.Context, salesOrderID int64) ([]ListSalesOrderItemsRow, error) {
	rows, err := q.db.Query(ctx, listSalesOrderItems, salesOrderID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListSalesOrderItemsRow
	for rows.Next() {
		var i ListSalesOrderItemsRow
		if err := rows.Scan(
			&i.ID,
			&i.SalesOrderID,
			&i.ProductID,
			&i.Quantity,
			&i.UnitPrice,
			&i.DiscountPercent,
			&i.DiscountAmount,
			&i.Subtotal,
			&i.ProductUnitID,
			&i.UnitID,
			&i.UnitName,
			&i.UnitSymbol,
			&i.ConversionFactor,
			&i.BaseQuantity,
			&i.MinPurchase,
			&i.Code,
			&i.Name,
			&i.MembershipTier,
			&i.MembershipDiscountAmount,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listSalesOrders = `-- name: ListSalesOrders :many
SELECT o.id, o.so_number, o.customer_id, o.warehouse_id, o.sales_id, o.store_id, o.order_date::text AS order_date, o.status, o.order_type, o.source_type,
       o.subtotal, o.tax_amount, o.discount_amount, o.total_amount, o.paid_amount, o.remaining_amount,
       o.shipping_cost, o.shipping_address, o.notes, o.received_proof_url, o.delivery_date, o.created_at, o.updated_at,
       c.name AS customer_name, se.name AS sales_name, w.name AS warehouse_name,
       -- POS transaction list: the cashier who rang the sale (via its shift),
       -- falling back to the field-sales rep for regular orders; plus line and
       -- unit counts so the list can show "N (M)" without fetching items.
       -- cu (the till operator) is a users.id join and stays; se is the
       -- employees row sales_id points at. See GetSalesOrderByID.
       COALESCE(cu.name, se.name, '') AS cashier_name,
       (SELECT count(*) FROM sales_order_items i WHERE i.sales_order_id = o.id)::int AS line_count,
       (SELECT COALESCE(SUM(i.quantity), 0) FROM sales_order_items i WHERE i.sales_order_id = o.id)::numeric AS item_qty,
       o.payment_terms,
       COALESCE((SELECT p.payment_method FROM payments p JOIN invoices i ON i.id = p.payable_id WHERE (p.payable_type = 'App\Models\Invoice' OR p.payable_type = 'invoice') AND i.sales_order_id = o.id ORDER BY p.id DESC LIMIT 1), '')::text AS payment_method
FROM sales_orders o
LEFT JOIN customers c ON c.id = o.customer_id
LEFT JOIN employees se ON se.id = o.sales_id
LEFT JOIN warehouses w ON w.id = o.warehouse_id
LEFT JOIN cashier_shifts cs ON cs.id = o.shift_id
LEFT JOIN users cu ON cu.id = cs.cashier_id
WHERE ($3::text IS NULL OR (o.so_number ILIKE '%' || $3 || '%' OR o.customer_id IN (SELECT id FROM customers WHERE name ILIKE '%' || $3 || '%') OR o.sales_id IN (SELECT id FROM employees WHERE name ILIKE '%' || $3 || '%') OR o.shipping_address ILIKE '%' || $3 || '%'))
  AND ($4::text IS NULL OR o.status = ANY(string_to_array($4, ',')))
  AND ($5::boolean IS NOT TRUE OR o.status NOT IN ('draft', 'pending_approval', 'blocked_overdue'))
  -- Warehouse packing list: exclude store-pickup orders (Ambil Sendiri di
  -- Toko). The courier chain (picking/shipping) never touches them — the POS
  -- till hands them over. Marker mirrors isPickupOrder in internal/sales.
  AND ($6::boolean IS NOT TRUE OR o.shipping_address IS NULL OR o.shipping_address !~* '[[]ambil sendiri|[]]ambil di toko|\[ambil sendiri')
  -- POS Ambil Toko: the inverse of exclude_pickup, applied in SQL so paging
  -- and COUNT agree. Same marker as isPickupOrder.
  AND ($7::boolean IS NOT TRUE OR o.shipping_address ~* '[[]ambil sendiri|[]]ambil di toko|\[ambil sendiri')
  AND ($8::bigint IS NULL OR $8::bigint <= 0 OR o.customer_id = $8)
  AND ($9::text IS NULL OR o.order_type = $9)
  AND ($10::text IS NULL OR o.source_type = $10)
  AND ($11::date IS NULL OR o.order_date >= $11)
  AND ($12::date IS NULL OR o.order_date <= $12)
  AND ($13::bigint IS NULL OR o.store_id = $13)
  -- Store-scoped callers see their stores' orders PLUS unbound orders
  -- (o.store_id IS NULL) — e-commerce checkout is not tied to a physical
  -- store, so those must stay visible to ERP operators for fulfilment.
  AND ($14::bigint[] IS NULL OR o.store_id IS NULL OR o.store_id = ANY($14))
ORDER BY
  CASE WHEN $15::text = 'so_number' AND ($16::text = 'asc' OR $16::text IS NULL) THEN o.so_number END ASC,
  CASE WHEN $15::text = 'so_number' AND $16::text = 'desc' THEN o.so_number END DESC,
  CASE WHEN $15::text = 'customer_name' AND ($16::text = 'asc' OR $16::text IS NULL) THEN c.name END ASC NULLS LAST,
  CASE WHEN $15::text = 'customer_name' AND $16::text = 'desc' THEN c.name END DESC NULLS LAST,
  CASE WHEN $15::text = 'sales_name' AND ($16::text = 'asc' OR $16::text IS NULL) THEN se.name END ASC NULLS LAST,
  CASE WHEN $15::text = 'sales_name' AND $16::text = 'desc' THEN se.name END DESC NULLS LAST,
  CASE WHEN $15::text = 'order_date' AND ($16::text = 'asc' OR $16::text IS NULL) THEN o.order_date END ASC,
  CASE WHEN $15::text = 'order_date' AND $16::text = 'desc' THEN o.order_date END DESC,
  CASE WHEN $15::text = 'status' AND ($16::text = 'asc' OR $16::text IS NULL) THEN o.status END ASC,
  CASE WHEN $15::text = 'status' AND $16::text = 'desc' THEN o.status END DESC,
  CASE WHEN $15::text = 'total_amount' AND ($16::text = 'asc' OR $16::text IS NULL) THEN o.total_amount END ASC,
  CASE WHEN $15::text = 'total_amount' AND $16::text = 'desc' THEN o.total_amount END DESC,
  CASE WHEN $15::text = 'created_at' AND ($16::text = 'asc' OR $16::text IS NULL) THEN o.created_at END ASC,
  CASE WHEN $15::text = 'created_at' AND $16::text = 'desc' THEN o.created_at END DESC,
  o.id DESC
LIMIT $1 OFFSET $2
`

type ListSalesOrdersParams struct {
	Limit             int32       `json:"limit"`
	Offset            int32       `json:"offset"`
	Search            pgtype.Text `json:"search"`
	Status            pgtype.Text `json:"status"`
	ExcludeUnapproved pgtype.Bool `json:"exclude_unapproved"`
	ExcludePickup     pgtype.Bool `json:"exclude_pickup"`
	PickupOnly        pgtype.Bool `json:"pickup_only"`
	CustomerID        pgtype.Int8 `json:"customer_id"`
	OrderType         pgtype.Text `json:"order_type"`
	SourceType        pgtype.Text `json:"source_type"`
	DateFrom          pgtype.Date `json:"date_from"`
	DateTo            pgtype.Date `json:"date_to"`
	StoreID           pgtype.Int8 `json:"store_id"`
	AllowedStoreIds   []int64     `json:"allowed_store_ids"`
	SortBy            pgtype.Text `json:"sort_by"`
	SortDir           pgtype.Text `json:"sort_dir"`
}

type ListSalesOrdersRow struct {
	ID               int64              `json:"id"`
	SoNumber         string             `json:"so_number"`
	CustomerID       int64              `json:"customer_id"`
	WarehouseID      pgtype.Int8        `json:"warehouse_id"`
	SalesID          pgtype.Int8        `json:"sales_id"`
	StoreID          pgtype.Int8        `json:"store_id"`
	OrderDate        string             `json:"order_date"`
	Status           string             `json:"status"`
	OrderType        string             `json:"order_type"`
	SourceType       pgtype.Text        `json:"source_type"`
	Subtotal         decimal.Decimal    `json:"subtotal"`
	TaxAmount        decimal.Decimal    `json:"tax_amount"`
	DiscountAmount   decimal.Decimal    `json:"discount_amount"`
	TotalAmount      decimal.Decimal    `json:"total_amount"`
	PaidAmount       decimal.Decimal    `json:"paid_amount"`
	RemainingAmount  decimal.Decimal    `json:"remaining_amount"`
	ShippingCost     decimal.Decimal    `json:"shipping_cost"`
	ShippingAddress  pgtype.Text        `json:"shipping_address"`
	Notes            pgtype.Text        `json:"notes"`
	ReceivedProofUrl pgtype.Text        `json:"received_proof_url"`
	DeliveryDate     pgtype.Date        `json:"delivery_date"`
	CreatedAt        pgtype.Timestamptz `json:"created_at"`
	UpdatedAt        pgtype.Timestamptz `json:"updated_at"`
	CustomerName     pgtype.Text        `json:"customer_name"`
	SalesName        pgtype.Text        `json:"sales_name"`
	WarehouseName    pgtype.Text        `json:"warehouse_name"`
	CashierName      string             `json:"cashier_name"`
	LineCount        int32              `json:"line_count"`
	ItemQty          decimal.Decimal    `json:"item_qty"`
	PaymentTerms     int32              `json:"payment_terms"`
	PaymentMethod    string             `json:"payment_method"`
}

func (q *Queries) ListSalesOrders(ctx context.Context, arg ListSalesOrdersParams) ([]ListSalesOrdersRow, error) {
	rows, err := q.db.Query(ctx, listSalesOrders,
		arg.Limit,
		arg.Offset,
		arg.Search,
		arg.Status,
		arg.ExcludeUnapproved,
		arg.ExcludePickup,
		arg.PickupOnly,
		arg.CustomerID,
		arg.OrderType,
		arg.SourceType,
		arg.DateFrom,
		arg.DateTo,
		arg.StoreID,
		arg.AllowedStoreIds,
		arg.SortBy,
		arg.SortDir,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListSalesOrdersRow
	for rows.Next() {
		var i ListSalesOrdersRow
		if err := rows.Scan(
			&i.ID,
			&i.SoNumber,
			&i.CustomerID,
			&i.WarehouseID,
			&i.SalesID,
			&i.StoreID,
			&i.OrderDate,
			&i.Status,
			&i.OrderType,
			&i.SourceType,
			&i.Subtotal,
			&i.TaxAmount,
			&i.DiscountAmount,
			&i.TotalAmount,
			&i.PaidAmount,
			&i.RemainingAmount,
			&i.ShippingCost,
			&i.ShippingAddress,
			&i.Notes,
			&i.ReceivedProofUrl,
			&i.DeliveryDate,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.CustomerName,
			&i.SalesName,
			&i.WarehouseName,
			&i.CashierName,
			&i.LineCount,
			&i.ItemQty,
			&i.PaymentTerms,
			&i.PaymentMethod,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listSalesReturnItems = `-- name: ListSalesReturnItems :many
SELECT i.id, i.sales_return_id, i.sales_order_item_id, i.product_id, i.quantity, i.unit_price, i.refund_amount, i.reason, i.condition, i.restocked, i.created_at,
       p.name AS product_name, p.code AS product_code, COALESCE(soi.unit_symbol, '') AS unit_symbol
FROM sales_return_items i
JOIN products p ON p.id = i.product_id
LEFT JOIN sales_order_items soi ON soi.id = i.sales_order_item_id
WHERE i.sales_return_id=$1 ORDER BY i.id
`

type ListSalesReturnItemsRow struct {
	ID               int64              `json:"id"`
	SalesReturnID    int64              `json:"sales_return_id"`
	SalesOrderItemID int64              `json:"sales_order_item_id"`
	ProductID        int64              `json:"product_id"`
	Quantity         decimal.Decimal    `json:"quantity"`
	UnitPrice        decimal.Decimal    `json:"unit_price"`
	RefundAmount     decimal.Decimal    `json:"refund_amount"`
	Reason           pgtype.Text        `json:"reason"`
	Condition        string             `json:"condition"`
	Restocked        bool               `json:"restocked"`
	CreatedAt        pgtype.Timestamptz `json:"created_at"`
	ProductName      string             `json:"product_name"`
	ProductCode      string             `json:"product_code"`
	UnitSymbol       string             `json:"unit_symbol"`
}

func (q *Queries) ListSalesReturnItems(ctx context.Context, salesReturnID int64) ([]ListSalesReturnItemsRow, error) {
	rows, err := q.db.Query(ctx, listSalesReturnItems, salesReturnID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListSalesReturnItemsRow
	for rows.Next() {
		var i ListSalesReturnItemsRow
		if err := rows.Scan(
			&i.ID,
			&i.SalesReturnID,
			&i.SalesOrderItemID,
			&i.ProductID,
			&i.Quantity,
			&i.UnitPrice,
			&i.RefundAmount,
			&i.Reason,
			&i.Condition,
			&i.Restocked,
			&i.CreatedAt,
			&i.ProductName,
			&i.ProductCode,
			&i.UnitSymbol,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listSalesReturns = `-- name: ListSalesReturns :many
SELECT r.id, r.return_number, r.sales_order_id, r.customer_id, r.warehouse_id, r.return_date::text AS return_date,
       r.refund_amount, r.refund_method, r.status, r.reason, r.created_by, r.created_at, r.updated_at,
       so.so_number, c.name AS customer_name
FROM sales_returns r
JOIN sales_orders so ON so.id = r.sales_order_id
JOIN customers c ON c.id = r.customer_id
WHERE ($3::bigint IS NULL OR $3::bigint <= 0 OR r.sales_order_id = $3)
  AND ($4::bigint IS NULL OR $4::bigint <= 0 OR r.customer_id = $4)
  AND ($5::bigint IS NULL OR $5::bigint <= 0 OR so.store_id = $5)
  -- Mirror ListSalesOrders: orders unbound to a store (store_id IS NULL)
  -- stay visible to every operator. NOTE: current checkout attributes
  -- e-commerce orders to the first active store, so the NULL branch is
  -- defensive until order binding changes.
  AND ($6::bigint[] IS NULL OR so.store_id IS NULL OR so.store_id = ANY($6))
ORDER BY r.id DESC
LIMIT $1 OFFSET $2
`

type ListSalesReturnsParams struct {
	Limit           int32       `json:"limit"`
	Offset          int32       `json:"offset"`
	SalesOrderID    pgtype.Int8 `json:"sales_order_id"`
	CustomerID      pgtype.Int8 `json:"customer_id"`
	StoreID         pgtype.Int8 `json:"store_id"`
	AllowedStoreIds []int64     `json:"allowed_store_ids"`
}

type ListSalesReturnsRow struct {
	ID           int64              `json:"id"`
	ReturnNumber string             `json:"return_number"`
	SalesOrderID int64              `json:"sales_order_id"`
	CustomerID   int64              `json:"customer_id"`
	WarehouseID  pgtype.Int8        `json:"warehouse_id"`
	ReturnDate   string             `json:"return_date"`
	RefundAmount decimal.Decimal    `json:"refund_amount"`
	RefundMethod string             `json:"refund_method"`
	Status       string             `json:"status"`
	Reason       pgtype.Text        `json:"reason"`
	CreatedBy    pgtype.Int8        `json:"created_by"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	SoNumber     string             `json:"so_number"`
	CustomerName string             `json:"customer_name"`
}

func (q *Queries) ListSalesReturns(ctx context.Context, arg ListSalesReturnsParams) ([]ListSalesReturnsRow, error) {
	rows, err := q.db.Query(ctx, listSalesReturns,
		arg.Limit,
		arg.Offset,
		arg.SalesOrderID,
		arg.CustomerID,
		arg.StoreID,
		arg.AllowedStoreIds,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListSalesReturnsRow
	for rows.Next() {
		var i ListSalesReturnsRow
		if err := rows.Scan(
			&i.ID,
			&i.ReturnNumber,
			&i.SalesOrderID,
			&i.CustomerID,
			&i.WarehouseID,
			&i.ReturnDate,
			&i.RefundAmount,
			&i.RefundMethod,
			&i.Status,
			&i.Reason,
			&i.CreatedBy,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.SoNumber,
			&i.CustomerName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listSalesVouchers = `-- name: ListSalesVouchers :many
SELECT id, voucher_number, type, description, voucher_date::text AS voucher_date, amount, status, created_by, created_at, updated_at, expired_at
FROM sales_vouchers
WHERE ($3::text IS NULL OR status = $3)
  AND ($4::text IS NULL OR type = $4)
  AND ($5::text IS NULL OR voucher_number ILIKE '%' || $5 || '%')
ORDER BY id DESC LIMIT $1 OFFSET $2
`

type ListSalesVouchersParams struct {
	Limit         int32       `json:"limit"`
	Offset        int32       `json:"offset"`
	Status        pgtype.Text `json:"status"`
	Type          pgtype.Text `json:"type"`
	VoucherNumber pgtype.Text `json:"voucher_number"`
}

type ListSalesVouchersRow struct {
	ID            int64              `json:"id"`
	VoucherNumber string             `json:"voucher_number"`
	Type          string             `json:"type"`
	Description   pgtype.Text        `json:"description"`
	VoucherDate   string             `json:"voucher_date"`
	Amount        decimal.Decimal    `json:"amount"`
	Status        string             `json:"status"`
	CreatedBy     pgtype.Int8        `json:"created_by"`
	CreatedAt     pgtype.Timestamptz `json:"created_at"`
	UpdatedAt     pgtype.Timestamptz `json:"updated_at"`
	ExpiredAt     pgtype.Date        `json:"expired_at"`
}

func (q *Queries) ListSalesVouchers(ctx context.Context, arg ListSalesVouchersParams) ([]ListSalesVouchersRow, error) {
	rows, err := q.db.Query(ctx, listSalesVouchers,
		arg.Limit,
		arg.Offset,
		arg.Status,
		arg.Type,
		arg.VoucherNumber,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListSalesVouchersRow
	for rows.Next() {
		var i ListSalesVouchersRow
		if err := rows.Scan(
			&i.ID,
			&i.VoucherNumber,
			&i.Type,
			&i.Description,
			&i.VoucherDate,
			&i.Amount,
			&i.Status,
			&i.CreatedBy,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.ExpiredAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const myOrdersSummary = `-- name: MyOrdersSummary :one
SELECT
  count(*) FILTER (WHERE status IN ('pending_approval', 'draft') OR (status IN ('confirmed', 'invoiced') AND (paid_amount < total_amount OR paid_amount = 0)))::int AS pending_count,
  count(*) FILTER (WHERE (status = 'paid' OR (status IN ('confirmed', 'invoiced') AND paid_amount >= total_amount AND total_amount > 0) OR status = 'picking'))::int AS processing_count,
  count(*) FILTER (WHERE status = 'shipped')::int AS shipping_count,
  count(*) FILTER (WHERE status = 'delivered')::int AS delivered_count,
  count(*) FILTER (WHERE status IN ('cancelled', 'rejected'))::int AS cancelled_count
FROM sales_orders
WHERE customer_id = $1 AND order_type = 'ecommerce'
`

type MyOrdersSummaryRow struct {
	PendingCount    int32 `json:"pending_count"`
	ProcessingCount int32 `json:"processing_count"`
	ShippingCount   int32 `json:"shipping_count"`
	DeliveredCount  int32 `json:"delivered_count"`
	CancelledCount  int32 `json:"cancelled_count"`
}

func (q *Queries) MyOrdersSummary(ctx context.Context, customerID int64) (MyOrdersSummaryRow, error) {
	row := q.db.QueryRow(ctx, myOrdersSummary, customerID)
	var i MyOrdersSummaryRow
	err := row.Scan(
		&i.PendingCount,
		&i.ProcessingCount,
		&i.ShippingCount,
		&i.DeliveredCount,
		&i.CancelledCount,
	)
	return i, err
}

const releaseStock = `-- name: ReleaseStock :execrows
UPDATE stocks SET reserved_quantity = GREATEST(0, reserved_quantity - $3), last_updated_at = now()
WHERE product_id=$1 AND warehouse_id=$2
`

type ReleaseStockParams struct {
	ProductID        int64           `json:"product_id"`
	WarehouseID      int64           `json:"warehouse_id"`
	ReservedQuantity decimal.Decimal `json:"reserved_quantity"`
}

func (q *Queries) ReleaseStock(ctx context.Context, arg ReleaseStockParams) (int64, error) {
	result, err := q.db.Exec(ctx, releaseStock, arg.ProductID, arg.WarehouseID, arg.ReservedQuantity)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const reserveStock = `-- name: ReserveStock :exec
INSERT INTO stocks (product_id, warehouse_id, quantity, reserved_quantity, last_updated_at)
VALUES ($1,$2,0,$3,now())
ON CONFLICT (product_id, warehouse_id)
DO UPDATE SET reserved_quantity = stocks.reserved_quantity + $3, last_updated_at = now()
`

type ReserveStockParams struct {
	ProductID        int64           `json:"product_id"`
	WarehouseID      int64           `json:"warehouse_id"`
	ReservedQuantity decimal.Decimal `json:"reserved_quantity"`
}

func (q *Queries) ReserveStock(ctx context.Context, arg ReserveStockParams) error {
	_, err := q.db.Exec(ctx, reserveStock, arg.ProductID, arg.WarehouseID, arg.ReservedQuantity)
	return err
}

const setSalesOrderStatus = `-- name: SetSalesOrderStatus :execrows
UPDATE sales_orders SET status=$2, updated_at=now() WHERE id=$1
`

type SetSalesOrderStatusParams struct {
	ID     int64  `json:"id"`
	Status string `json:"status"`
}

func (q *Queries) SetSalesOrderStatus(ctx context.Context, arg SetSalesOrderStatusParams) (int64, error) {
	result, err := q.db.Exec(ctx, setSalesOrderStatus, arg.ID, arg.Status)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const setSalesReturnItemCondition = `-- name: SetSalesReturnItemCondition :one
UPDATE sales_return_items
SET condition=$2, restocked=$3
WHERE id=$1
RETURNING id, sales_return_id, sales_order_item_id, product_id, quantity, unit_price, refund_amount, reason, condition, restocked, created_at
`

type SetSalesReturnItemConditionParams struct {
	ID        int64  `json:"id"`
	Condition string `json:"condition"`
	Restocked bool   `json:"restocked"`
}

func (q *Queries) SetSalesReturnItemCondition(ctx context.Context, arg SetSalesReturnItemConditionParams) (SalesReturnItem, error) {
	row := q.db.QueryRow(ctx, setSalesReturnItemCondition, arg.ID, arg.Condition, arg.Restocked)
	var i SalesReturnItem
	err := row.Scan(
		&i.ID,
		&i.SalesReturnID,
		&i.SalesOrderItemID,
		&i.ProductID,
		&i.Quantity,
		&i.UnitPrice,
		&i.RefundAmount,
		&i.Reason,
		&i.Condition,
		&i.Restocked,
		&i.CreatedAt,
	)
	return i, err
}

const stockAvailable = `-- name: StockAvailable :one
SELECT CAST(COALESCE(quantity, 0) - COALESCE(reserved_quantity, 0) AS numeric(12,4))
FROM stocks WHERE product_id=$1 AND warehouse_id=$2
`

type StockAvailableParams struct {
	ProductID   int64 `json:"product_id"`
	WarehouseID int64 `json:"warehouse_id"`
}

func (q *Queries) StockAvailable(ctx context.Context, arg StockAvailableParams) (decimal.Decimal, error) {
	row := q.db.QueryRow(ctx, stockAvailable, arg.ProductID, arg.WarehouseID)
	var column_1 decimal.Decimal
	err := row.Scan(&column_1)
	return column_1, err
}

const sumReturnedQtyByOrderItem = `-- name: SumReturnedQtyByOrderItem :one
SELECT COALESCE(SUM(quantity),0)::numeric AS total FROM sales_return_items
WHERE sales_order_item_id=$1
`

func (q *Queries) SumReturnedQtyByOrderItem(ctx context.Context, salesOrderItemID int64) (decimal.Decimal, error) {
	row := q.db.QueryRow(ctx, sumReturnedQtyByOrderItem, salesOrderItemID)
	var total decimal.Decimal
	err := row.Scan(&total)
	return total, err
}

const updateSalesOrder = `-- name: UpdateSalesOrder :execrows
UPDATE sales_orders SET so_number=$2, customer_id=$3, warehouse_id=$4, sales_id=$5,
       order_date=$6, status=$7, order_type=$8, subtotal=$9, tax_amount=$10, discount_amount=$11,
       total_amount=$12, paid_amount=$13, remaining_amount=$14, shipping_cost=$15,
       shipping_address=$16, notes=$17, delivery_date=$18, store_id=$19, source_type=$20,
       payment_terms=$21, updated_at=now()
WHERE id=$1
`

type UpdateSalesOrderParams struct {
	ID              int64           `json:"id"`
	SoNumber        string          `json:"so_number"`
	CustomerID      int64           `json:"customer_id"`
	WarehouseID     pgtype.Int8     `json:"warehouse_id"`
	SalesID         pgtype.Int8     `json:"sales_id"`
	OrderDate       pgtype.Date     `json:"order_date"`
	Status          string          `json:"status"`
	OrderType       string          `json:"order_type"`
	Subtotal        decimal.Decimal `json:"subtotal"`
	TaxAmount       decimal.Decimal `json:"tax_amount"`
	DiscountAmount  decimal.Decimal `json:"discount_amount"`
	TotalAmount     decimal.Decimal `json:"total_amount"`
	PaidAmount      decimal.Decimal `json:"paid_amount"`
	RemainingAmount decimal.Decimal `json:"remaining_amount"`
	ShippingCost    decimal.Decimal `json:"shipping_cost"`
	ShippingAddress pgtype.Text     `json:"shipping_address"`
	Notes           pgtype.Text     `json:"notes"`
	DeliveryDate    pgtype.Date     `json:"delivery_date"`
	StoreID         pgtype.Int8     `json:"store_id"`
	SourceType      pgtype.Text     `json:"source_type"`
	PaymentTerms    int32           `json:"payment_terms"`
}

func (q *Queries) UpdateSalesOrder(ctx context.Context, arg UpdateSalesOrderParams) (int64, error) {
	result, err := q.db.Exec(ctx, updateSalesOrder,
		arg.ID,
		arg.SoNumber,
		arg.CustomerID,
		arg.WarehouseID,
		arg.SalesID,
		arg.OrderDate,
		arg.Status,
		arg.OrderType,
		arg.Subtotal,
		arg.TaxAmount,
		arg.DiscountAmount,
		arg.TotalAmount,
		arg.PaidAmount,
		arg.RemainingAmount,
		arg.ShippingCost,
		arg.ShippingAddress,
		arg.Notes,
		arg.DeliveryDate,
		arg.StoreID,
		arg.SourceType,
		arg.PaymentTerms,
	)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updateSalesOrderNotes = `-- name: UpdateSalesOrderNotes :execrows
UPDATE sales_orders SET notes=$2, updated_at=now() WHERE id=$1
`

type UpdateSalesOrderNotesParams struct {
	ID    int64       `json:"id"`
	Notes pgtype.Text `json:"notes"`
}

func (q *Queries) UpdateSalesOrderNotes(ctx context.Context, arg UpdateSalesOrderNotesParams) (int64, error) {
	result, err := q.db.Exec(ctx, updateSalesOrderNotes, arg.ID, arg.Notes)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updateSalesStockRow = `-- name: UpdateSalesStockRow :execrows
UPDATE stocks SET quantity=$2, reserved_quantity=$3, last_updated_at=now(), updated_at=now()
WHERE id=$1
`

type UpdateSalesStockRowParams struct {
	ID               int64           `json:"id"`
	Quantity         decimal.Decimal `json:"quantity"`
	ReservedQuantity decimal.Decimal `json:"reserved_quantity"`
}

func (q *Queries) UpdateSalesStockRow(ctx context.Context, arg UpdateSalesStockRowParams) (int64, error) {
	result, err := q.db.Exec(ctx, updateSalesStockRow, arg.ID, arg.Quantity, arg.ReservedQuantity)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updateSalesVoucherStatus = `-- name: UpdateSalesVoucherStatus :execrows
UPDATE sales_vouchers SET status=$2, updated_at=now() WHERE id=$1
`

type UpdateSalesVoucherStatusParams struct {
	ID     int64  `json:"id"`
	Status string `json:"status"`
}

func (q *Queries) UpdateSalesVoucherStatus(ctx context.Context, arg UpdateSalesVoucherStatusParams) (int64, error) {
	result, err := q.db.Exec(ctx, updateSalesVoucherStatus, arg.ID, arg.Status)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}
