Files
aura-crm/production/backend/internal/document/batch.go
T

135 lines
4.0 KiB
Go

package document
import (
"context"
"fmt"
"strings"
"time"
"production/internal/auth"
"production/internal/authz"
"production/internal/doctemplates"
"production/internal/pdfgen"
"github.com/gofiber/fiber/v2"
)
type batchItem struct {
model, color, price string
}
type batchClient struct {
id string
createdAt time.Time
client pdfgen.Client
items []batchItem
}
func (h *Handler) loadBatch(ctx context.Context, batchID string) (batchClient, error) {
var bc batchClient
var clientEmail, clientINN, clientKPP, clientCompanyAddress *string
err := h.db.QueryRow(ctx, `
SELECT cb.id, cb.created_at,
cl.type, cl.name, cl.phone, cl.email, cl.inn, cl.kpp, cl.company_address
FROM cartridge_batches cb JOIN clients cl ON cl.id = cb.client_id
WHERE cb.id = $1::uuid`, batchID,
).Scan(&bc.id, &bc.createdAt, &bc.client.Type, &bc.client.Name, &bc.client.Phone,
&clientEmail, &clientINN, &clientKPP, &clientCompanyAddress)
if err != nil {
return bc, err
}
bc.client.Email = deref(clientEmail)
bc.client.INN = deref(clientINN)
bc.client.KPP = deref(clientKPP)
bc.client.CompanyAddress = deref(clientCompanyAddress)
rows, err := h.db.Query(ctx,
`SELECT model, color, price::text FROM cartridge_items WHERE batch_id = $1::uuid ORDER BY position`, batchID)
if err != nil {
return bc, err
}
defer rows.Close()
for rows.Next() {
var it batchItem
var price *string
if err := rows.Scan(&it.model, &it.color, &price); err != nil {
return bc, err
}
it.price = deref(price)
bc.items = append(bc.items, it)
}
return bc, rows.Err()
}
func cartridgeItemName(model, color string) string {
return fmt.Sprintf("Заправка картриджа %s (%s)", model, color)
}
func (h *Handler) BatchInvoice(c *fiber.Ctx) error {
id := c.Params("id")
ctx := context.Background()
if err := authz.CheckBatchAccess(ctx, h.db, id, auth.StaffPermissions(c), auth.StaffID(c)); err != nil {
return err
}
bc, err := h.loadBatch(ctx, id)
if err != nil {
return h.notFoundOr500(c, "cartridge batch", id, err)
}
business, err := h.loadBusiness(ctx)
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": "internal error"})
}
blocks, err := doctemplates.Fetch(ctx, h.db, doctemplates.KindInvoice)
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": "internal error"})
}
items := make([]pdfgen.LineItem, len(bc.items))
for i, it := range bc.items {
items[i] = pdfgen.LineItem{Name: cartridgeItemName(it.model, it.color), Qty: 1, Price: it.price}
}
doc := pdfgen.InvoiceDoc{ID: bc.id, CreatedAt: bc.createdAt, Items: items}
pdfBytes, err := pdfgen.GenerateInvoice(business, bc.client, doc, blocks)
return h.servePDF(c, "invoice", bc.id, pdfBytes, err)
}
func (h *Handler) BatchAct(c *fiber.Ctx) error {
id := c.Params("id")
ctx := context.Background()
if err := authz.CheckBatchAccess(ctx, h.db, id, auth.StaffPermissions(c), auth.StaffID(c)); err != nil {
return err
}
bc, err := h.loadBatch(ctx, id)
if err != nil {
return h.notFoundOr500(c, "cartridge batch", id, err)
}
business, err := h.loadBusiness(ctx)
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": "internal error"})
}
blocks, err := doctemplates.Fetch(ctx, h.db, doctemplates.KindAct)
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": "internal error"})
}
lines := make([]string, len(bc.items))
priceLines := make([]pdfgen.LineItem, len(bc.items))
for i, it := range bc.items {
lines[i] = fmt.Sprintf("%d. %s", i+1, cartridgeItemName(it.model, it.color))
priceLines[i] = pdfgen.LineItem{Price: it.price}
}
doc := pdfgen.ActDoc{
ID: bc.id,
CreatedAt: bc.createdAt,
IntroLine: fmt.Sprintf("Исполнитель произвёл заправку/восстановление картриджей (%d шт.):", len(bc.items)),
WorkSummary: strings.Join(lines, "\n"),
Total: sumLineItemPrices(priceLines),
}
pdfBytes, err := pdfgen.GenerateAct(business, bc.client, doc, blocks)
return h.servePDF(c, "act", bc.id, pdfBytes, err)
}