Files
vapor-po/Sources/App/Controllers/View/PurchaseOrderViewController.swift

181 lines
4.9 KiB
Swift

import Fluent
import Vapor
struct PurchaseOrderViewController: RouteCollection {
private let employeesApi = EmployeeApiController()
private let branches = VendorBranchDB()
private let api = ApiController()
private let api2 = PurchaseOrderDB()
func boot(routes: any RoutesBuilder) throws {
let pos = routes.protected.grouped("purchase-orders")
pos.get(use: index(req:))
pos.post(use: create(req:))
pos.group(":id") {
$0.get(use: detail(req:))
}
}
@Sendable
func index(req: Request) async throws -> View {
let params = try? req.query.decode(PurchaseOrderIndex.self)
let purchaseOrdersPage = try await api2.fetchPage(params?.page ?? 1, limit: params?.limit ?? 50, on: req.db)
let branches = try await self.branches.getBranches(req: req)
let employees = try await employeesApi.index(req: req)
req.logger.debug("Branches: \(branches)")
return try await req.view.render(
"purchaseOrders/index",
PurchaseOrderCTX(
page: purchaseOrdersPage,
form: .create(branches: branches, employees: employees)
)
)
}
@Sendable
func detail(req: Request) async throws -> View {
guard let id = req.parameters.get("id", as: PurchaseOrder.IDValue.self) else {
throw Abort(.badRequest, reason: "Id not supplied.")
}
let purchaseOrder = try await api2.get(id: id, on: req.db)
return try await req.view.render("purchaseOrders/detail", ["purchaseOrder": purchaseOrder])
}
@Sendable
func create(req: Request) async throws -> View {
try PurchaseOrder.FormCreate.validate(content: req)
let createdById = try req.auth.require(User.self).requireID()
let create = try req.content.decode(PurchaseOrder.FormCreate.self).toCreate()
let purchaseOrder = try await api2.create(create, createdById: createdById, on: req.db)
return try await req.view.render("purchaseOrders/table-row", purchaseOrder)
}
}
private struct PurchaseOrderIndex: Content {
let page: Int?
let limit: Int?
}
private struct PurchaseOrderCTX: Content {
let purchaseOrders: [PurchaseOrder.DTO]
let page: Int
let limit: Int
let hasNext: Bool
let hasPrevious: Bool
let form: PurchaseOrderFormCTX?
init(page: Page<PurchaseOrder.DTO>, form: PurchaseOrderFormCTX?) {
self.purchaseOrders = page.items
self.page = page.metadata.page
self.limit = page.metadata.per
self.hasNext = page.metadata.hasNext
self.hasPrevious = page.metadata.page > 1
self.form = form
}
}
private extension PageMetadata {
var hasNext: Bool {
total > (page * per)
}
}
private struct PurchaseOrderFormCTX: Content {
let htmxForm: HtmxFormCTX<Context>
struct Context: Content {
let branches: [VendorBranch.FormDTO]
let employees: [Employee.DTO]
}
static func create(branches: [VendorBranch.FormDTO], employees: [Employee.DTO]) -> Self {
.init(htmxForm: .init(
formClass: "po-form",
formId: "po-form",
htmxTargetUrl: .post("/purchase-orders"),
htmxTarget: "#po-table-body",
htmxPushUrl: false,
htmxResetAfterRequest: true,
htmxSwapOob: nil,
htmxSwap: .afterbegin,
context: .init(branches: branches, employees: employees)
))
}
}
extension VendorBranch {
struct FormDTO: Content {
let id: UUID
let name: String
let vendor: Vendor.DTO
}
func toFormDTO() throws -> VendorBranch.FormDTO {
try .init(
id: requireID(),
name: name,
vendor: vendor.toDTO()
)
}
}
private extension PurchaseOrder {
struct FormCreate: Content {
let id: Int?
let workOrder: String?
let materials: String
let customer: String
let truckStock: Bool?
let createdForID: Employee.IDValue
let vendorBranchID: VendorBranch.IDValue
// TODO: Remove.
func toModel(createdByID: User.IDValue) -> PurchaseOrder {
.init(
id: id,
workOrder: workOrder != nil ? (workOrder == "" ? nil : Int(workOrder!)) : nil,
materials: materials,
customer: customer,
truckStock: truckStock ?? false,
createdByID: createdByID,
createdForID: createdForID,
vendorBranchID: vendorBranchID,
createdAt: nil,
updatedAt: nil
)
}
func toCreate() -> PurchaseOrder.Create {
.init(
id: id,
workOrder: workOrder != nil ? (workOrder == "" ? nil : Int(workOrder!)) : nil,
materials: materials,
customer: customer,
truckStock: truckStock,
createdForID: createdForID,
vendorBranchID: vendorBranchID
)
}
}
}
private extension VendorBranchDB {
func getBranches(req: Request) async throws -> [VendorBranch.FormDTO] {
try await VendorBranch.query(on: req.db)
.with(\.$vendor)
.all()
.map { try $0.toFormDTO() }
}
}
extension PurchaseOrder.FormCreate: Validatable {
static func validations(_ validations: inout Validations) {
validations.add("materials", as: String.self, is: !.empty)
validations.add("customer", as: String.self, is: !.empty)
}
}