Files
vapor-po/Sources/DatabaseClientLive/PurchaseOrders.swift

175 lines
4.8 KiB
Swift

import DatabaseClient
import FluentKit
import Foundation
import SharedModels
public extension DatabaseClient.PurchaseOrders {
static func live(database: any Database) -> Self {
.init { create, createdById in
let model = try create.toModel(createdByID: createdById)
try await model.save(on: database)
return try model.toDTO()
} fetchAll: {
try await PurchaseOrderModel.allQuery(on: database)
.all()
.map { try $0.toDTO() }
} fetchPage: { request in
try await PurchaseOrderModel.allQuery(on: database)
.paginate(request)
.map { try $0.toDTO() }
} get: { id in
try await PurchaseOrderModel.allQuery(on: database)
.filter(\.$id == id)
.first()
.map { try $0.toDTO() }
} delete: { id in
guard let model = try await PurchaseOrderModel.find(id, on: database) else {
throw NotFoundError()
}
try await model.delete(on: database)
}
}
}
extension PurchaseOrder {
struct Migrate: AsyncMigration {
let name = "CreatePurchaseOrder"
func prepare(on database: any Database) async throws {
try await database.schema(PurchaseOrderModel.schema)
.field("id", .int, .identifier(auto: true))
.field("work_order", .int)
.field("customer", .string, .required)
.field("materials", .string, .required)
.field("truck_stock", .bool, .required)
.field("created_by_id", .uuid, .required, .references(UserModel.schema, "id"))
.field("created_for_id", .uuid, .required, .references(EmployeeModel.schema, "id"))
.field("vendor_branch_id", .uuid, .required, .references(VendorBranchModel.schema, "id"))
.field("created_at", .datetime)
.field("updated_at", .datetime)
.create()
}
func revert(on database: any Database) async throws {
try await database.schema(PurchaseOrderModel.schema).delete()
}
}
}
extension PurchaseOrder.Create {
func toModel(createdByID: User.ID) throws -> PurchaseOrderModel {
try validate()
return .init(
materials: materials,
customer: customer,
truckStock: truckStock ?? false,
createdByID: createdByID,
createdForID: createdForID,
vendorBranchID: vendorBranchID
)
}
func validate() throws {
guard !materials.isEmpty else {
throw ValidationError(message: "Materials should not be empty.")
}
guard !customer.isEmpty else {
throw ValidationError(message: "Customer should not be empty.")
}
}
}
/// The purchase order database model.
///
/// # NOTE: An initial purchase order should be created with an `id` higher than our current PO
/// so that subsequent PO's are generated with higher values than our current system produces.
/// once the first one is set, the rest will auto-increment from there.
final class PurchaseOrderModel: Model, Codable, @unchecked Sendable {
static let schema = "purchase_order"
@ID(custom: "id", generatedBy: .database)
var id: Int?
@Field(key: "work_order")
var workOrder: Int?
@Field(key: "materials")
var materials: String
@Field(key: "customer")
var customer: String
@Field(key: "truck_stock")
var truckStock: Bool
@Parent(key: "created_by_id")
var createdBy: UserModel
@Parent(key: "created_for_id")
var createdFor: EmployeeModel
@Parent(key: "vendor_branch_id")
var vendorBranch: VendorBranchModel
@Timestamp(key: "created_at", on: .create)
var createdAt: Date?
@Timestamp(key: "updated_at", on: .update)
var updatedAt: Date?
init() {}
init(
id: Int? = nil,
workOrder: Int? = nil,
materials: String,
customer: String,
truckStock: Bool,
createdByID: UserModel.IDValue,
createdForID: EmployeeModel.IDValue,
vendorBranchID: VendorBranchModel.IDValue,
createdAt: Date? = nil,
updatedAt: Date? = nil
) {
self.id = id
self.workOrder = workOrder
self.materials = materials
self.customer = customer
self.truckStock = truckStock
$createdBy.id = createdByID
$createdFor.id = createdForID
$vendorBranch.id = vendorBranchID
self.createdAt = createdAt
self.updatedAt = updatedAt
}
func toDTO() throws -> PurchaseOrder {
try .init(
id: requireID(),
workOrder: workOrder,
materials: materials,
customer: customer,
truckStock: truckStock,
createdBy: createdBy.toDTO(),
createdFor: createdFor.toDTO(),
vendorBranch: vendorBranch.toDTO(),
createdAt: createdAt,
updatedAt: updatedAt
)
}
static func allQuery(on db: any Database) -> QueryBuilder<PurchaseOrderModel> {
PurchaseOrderModel.query(on: db)
.sort(\.$id, .descending)
.with(\.$createdBy)
.with(\.$createdFor)
.with(\.$vendorBranch) { branch in
branch.with(\.$vendor)
}
}
}