181 lines
4.9 KiB
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)
|
|
}
|
|
}
|