feat: Working purchase order table and form.
This commit is contained in:
@@ -10,12 +10,12 @@ struct EmployeeViewController: RouteCollection {
|
||||
let employees = routes.protected.grouped("employees")
|
||||
employees.get(use: index(req:))
|
||||
employees.get("form", use: employeeForm(req:))
|
||||
employees.post(use: postEmployeeForm(req:))
|
||||
employees.post(use: create(req:))
|
||||
employees.group(":employeeID") {
|
||||
$0.get(use: editEmployee(req:))
|
||||
$0.delete(use: deleteEmployee(req:))
|
||||
$0.put(use: updateEmployee(req:))
|
||||
$0.post("toggle-active", use: toggleActiveEmployee(req:))
|
||||
$0.get(use: edit(req:))
|
||||
$0.delete(use: delete(req:))
|
||||
$0.put(use: update(req:))
|
||||
$0.post("toggle-active", use: toggleActive(req:))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,14 +25,13 @@ struct EmployeeViewController: RouteCollection {
|
||||
}
|
||||
|
||||
@Sendable
|
||||
func postEmployeeForm(req: Request) async throws -> View {
|
||||
func create(req: Request) async throws -> View {
|
||||
_ = try await api.createEmployee(req: req)
|
||||
let employees = try await api.getSortedEmployees(req: req)
|
||||
return try await req.view.render("employees/table", ["employees": employees])
|
||||
return try await req.view.render("employees/index", EmployeesCTX(oob: true, api: api, req: req))
|
||||
}
|
||||
|
||||
@Sendable
|
||||
func toggleActiveEmployee(req: Request) async throws -> View {
|
||||
func toggleActive(req: Request) async throws -> View {
|
||||
guard let employee = try await Employee.find(req.parameters.get("employeeID"), on: req.db) else {
|
||||
throw Abort(.notFound)
|
||||
}
|
||||
@@ -43,14 +42,14 @@ struct EmployeeViewController: RouteCollection {
|
||||
}
|
||||
|
||||
@Sendable
|
||||
func deleteEmployee(req: Request) async throws -> View {
|
||||
func delete(req: Request) async throws -> View {
|
||||
_ = try await api.deleteEmployee(req: req)
|
||||
let employees = try await api.getSortedEmployees(req: req)
|
||||
return try await req.view.render("employees/table", ["employees": employees])
|
||||
}
|
||||
|
||||
@Sendable
|
||||
func editEmployee(req: Request) async throws -> View {
|
||||
func edit(req: Request) async throws -> View {
|
||||
guard let employee = try await Employee.find(req.parameters.get("employeeID"), on: req.db) else {
|
||||
throw Abort(.notFound)
|
||||
}
|
||||
@@ -58,7 +57,7 @@ struct EmployeeViewController: RouteCollection {
|
||||
}
|
||||
|
||||
@Sendable
|
||||
func updateEmployee(req: Request) async throws -> View {
|
||||
func update(req: Request) async throws -> View {
|
||||
_ = try await api.updateEmployee(req: req)
|
||||
return try await req.view.render("employees/index", EmployeesCTX(oob: true, api: api, req: req))
|
||||
}
|
||||
@@ -88,12 +87,25 @@ private struct EmployeesCTX: Content {
|
||||
}
|
||||
|
||||
private struct EmployeeFormCTX: Content {
|
||||
let employee: Employee.DTO?
|
||||
let oob: Bool
|
||||
|
||||
let htmxForm: HtmxFormCTX<Context>
|
||||
|
||||
init(employee: Employee.DTO? = nil) {
|
||||
self.employee = employee
|
||||
self.oob = employee != nil
|
||||
self.htmxForm = .init(
|
||||
formClass: "employee-form",
|
||||
formId: "employee-form",
|
||||
htmxTargetUrl: employee?.id == nil ? .post("/employees") : .put("/employees/\(employee!.id!)"),
|
||||
htmxTarget: "#employee-table",
|
||||
htmxPushUrl: false,
|
||||
htmxResetAfterRequest: true,
|
||||
htmxSwapOob: nil,
|
||||
htmxSwap: employee == nil ? .outerHTML : nil,
|
||||
context: .init(employee: employee)
|
||||
)
|
||||
}
|
||||
|
||||
struct Context: Content {
|
||||
let employee: Employee.DTO?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,136 @@ struct PurchaseOrderViewController: RouteCollection {
|
||||
private let api = ApiController()
|
||||
|
||||
func boot(routes: any RoutesBuilder) throws {
|
||||
// Do something.
|
||||
let pos = routes.protected.grouped("purchase-orders")
|
||||
|
||||
pos.get(use: index(req:))
|
||||
pos.post(use: create(req:))
|
||||
}
|
||||
|
||||
@Sendable
|
||||
func index(req: Request) async throws -> View {
|
||||
let purchaseOrders = try await api.purchaseOrdersIndex(req: req)
|
||||
let branches = try await api.getBranches(req: req)
|
||||
let employees = try await api.employeesIndex(req: req)
|
||||
req.logger.info("Branches: \(branches)")
|
||||
return try await req.view.render(
|
||||
"purchaseOrders/index",
|
||||
PurchaseOrderCTX(
|
||||
purchaseOrders: purchaseOrders,
|
||||
form: .create(branches: branches, employees: employees)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
guard let employee = try await Employee.find(create.createdForID, on: req.db) else {
|
||||
throw Abort(.notFound, reason: "Employee not found.")
|
||||
}
|
||||
|
||||
guard employee.active else {
|
||||
throw Abort(.badRequest, reason: "Employee is not active, unable to generate a PO for in-active employees")
|
||||
}
|
||||
|
||||
let purchaseOrder = create.toModel(createdByID: createdById)
|
||||
try await purchaseOrder.save(on: req.db)
|
||||
|
||||
let purchaseOrders = try await api.purchaseOrdersIndex(req: req)
|
||||
return try await req.view.render("purchaseOrders/table", ["purchaseOrders": purchaseOrders])
|
||||
}
|
||||
}
|
||||
|
||||
private struct PurchaseOrderCTX: Content {
|
||||
let purchaseOrders: [PurchaseOrder.DTO]
|
||||
let form: PurchaseOrderFormCTX?
|
||||
}
|
||||
|
||||
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",
|
||||
htmxPushUrl: false,
|
||||
htmxResetAfterRequest: true,
|
||||
htmxSwapOob: nil,
|
||||
htmxSwap: .outerHTML,
|
||||
context: .init(branches: branches, employees: employees)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
extension VendorBranch {
|
||||
struct FormDTO: Content {
|
||||
let id: UUID
|
||||
let name: String
|
||||
let vendor: Vendor.DTO
|
||||
}
|
||||
|
||||
func toFormDTO() throws -> 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
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension ApiController {
|
||||
|
||||
func getBranches(req: Request) async throws -> [VendorBranch.FormDTO] {
|
||||
try await VendorBranch.query(on: req.db)
|
||||
.with(\.$vendor)
|
||||
// .sort(Vendor.self, \.$name)
|
||||
.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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ struct ViewController: RouteCollection {
|
||||
|
||||
private let api = ApiController()
|
||||
private let employees = EmployeeViewController()
|
||||
private let purchaseOrders = PurchaseOrderViewController()
|
||||
private let users = UserViewController()
|
||||
private let vendors = VendorViewController()
|
||||
|
||||
@@ -25,6 +26,7 @@ struct ViewController: RouteCollection {
|
||||
protected.post("logout", use: logout(req:))
|
||||
// protected.get("users", use: users(req:))
|
||||
try routes.register(collection: employees)
|
||||
try routes.register(collection: purchaseOrders)
|
||||
try routes.register(collection: users)
|
||||
try routes.register(collection: vendors)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user