basic online
This commit is contained in:
83
internal/database/actual-repo.go
Normal file
83
internal/database/actual-repo.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"Engine/internal/model"
|
||||
)
|
||||
|
||||
type ActualsRepo struct {
|
||||
db *DB
|
||||
}
|
||||
|
||||
func NewActualsRepo(db *DB) *ActualsRepo {
|
||||
return &ActualsRepo{db: db}
|
||||
}
|
||||
|
||||
func (r *ActualsRepo) Ingest(ctx context.Context, req model.IngestActualsRequest) (*model.Actual, error) {
|
||||
var deptID, glID int
|
||||
if err := r.db.QueryRowContext(ctx, `SELECT id FROM departments WHERE code=?`, req.DeptCode).Scan(&deptID); err != nil {
|
||||
return nil, fmt.Errorf("department %q not found: %w", req.DeptCode, err)
|
||||
}
|
||||
if err := r.db.QueryRowContext(ctx, `SELECT id FROM gl_accounts WHERE code=?`, req.GLCode).Scan(&glID); err != nil {
|
||||
return nil, fmt.Errorf("GL account %q not found: %w", req.GLCode, err)
|
||||
}
|
||||
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
INSERT INTO actuals (fiscal_year, fiscal_period, department_id, gl_account_id, amount, currency, source)
|
||||
VALUES (?,?,?,?,?,?,?)
|
||||
ON CONFLICT (fiscal_year, fiscal_period, department_id, gl_account_id)
|
||||
DO UPDATE SET amount=excluded.amount, source=excluded.source`,
|
||||
req.FiscalYear, req.FiscalPeriod, deptID, glID,
|
||||
req.Amount, req.Currency, req.Source,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("upsert actual: %w", err)
|
||||
}
|
||||
|
||||
a := &model.Actual{}
|
||||
err = r.db.QueryRowContext(ctx, `
|
||||
SELECT id, fiscal_year, fiscal_period, department_id, gl_account_id,
|
||||
amount, currency, source, ingested_at
|
||||
FROM actuals
|
||||
WHERE fiscal_year=? AND fiscal_period=? AND department_id=? AND gl_account_id=?`,
|
||||
req.FiscalYear, req.FiscalPeriod, deptID, glID,
|
||||
).Scan(
|
||||
&a.ID, &a.FiscalYear, &a.FiscalPeriod,
|
||||
&a.DepartmentID, &a.GLAccountID,
|
||||
&a.Amount, &a.Currency, &a.Source, &a.IngestedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetch ingested actual: %w", err)
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (r *ActualsRepo) ListByPeriod(ctx context.Context, fiscalYear, fiscalPeriod int, deptCode string) (map[string]float64, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
SELECT g.code, a.amount
|
||||
FROM actuals a
|
||||
JOIN departments d ON d.id = a.department_id
|
||||
JOIN gl_accounts g ON g.id = a.gl_account_id
|
||||
WHERE a.fiscal_year = ?
|
||||
AND a.fiscal_period = ?
|
||||
AND (? = '' OR d.code = ?)`,
|
||||
fiscalYear, fiscalPeriod, deptCode, deptCode,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list actuals: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
result := make(map[string]float64)
|
||||
for rows.Next() {
|
||||
var code string
|
||||
var amount float64
|
||||
if err := rows.Scan(&code, &amount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[code] += amount
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
Reference in New Issue
Block a user