feat: Fixes merge conflicts
This commit is contained in:
@@ -47,6 +47,7 @@ jobs:
|
|||||||
type=ref,event=branch
|
type=ref,event=branch
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
type=sha
|
type=sha
|
||||||
|
type=raw,value=prod
|
||||||
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If
|
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If
|
||||||
# the build succeeds, it pushes the image to GitHub Packages. It uses the `context` parameter to define the build's context
|
# the build succeeds, it pushes the image to GitHub Packages. It uses the `context` parameter to define the build's context
|
||||||
# as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)"
|
# as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)"
|
||||||
|
|||||||
67
README.md
Normal file
67
README.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# vapor-po
|
||||||
|
|
||||||
|
The website for generating purchase orders.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Generally the app should be ran through a docker container or docker-compose file. Examples are in
|
||||||
|
the `./docker` folder.
|
||||||
|
|
||||||
|
Images get built in the `CI` environment when a tag is pushed to the repository.
|
||||||
|
|
||||||
|
### Getting Started
|
||||||
|
|
||||||
|
When the application is first launched an admin user should be created in the running container.
|
||||||
|
Attach to the container using `docker exec` or `docker compose exec`, then run:
|
||||||
|
|
||||||
|
```
|
||||||
|
./App generate-admin --username "admin" --password "super-secret --confirmPassword "super-secret"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then login and generate user, employees, vendors, etc.
|
||||||
|
|
||||||
|
After the setup has been completed, then you should generate a mock purchase order and set the `id`
|
||||||
|
to the value you would like new purchase orders to start from. This should be done through calling
|
||||||
|
the api, as the web interface does not allow users to enter an id value.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
These examples use `httpie`, note the port is used for local development, in a production
|
||||||
|
environment you would just use the FQDN of where the application is running.
|
||||||
|
|
||||||
|
**Login**
|
||||||
|
|
||||||
|
```
|
||||||
|
http :8080/api/v1/login username="admin" password="super-secret" \
|
||||||
|
| jq '.["token"]' \
|
||||||
|
| pbcopy
|
||||||
|
```
|
||||||
|
|
||||||
|
**Set the token as environment variable**
|
||||||
|
|
||||||
|
```
|
||||||
|
export API_TOKEN=<clipboard contents>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Get the employees to copy an id to use for the purchase order**
|
||||||
|
|
||||||
|
```
|
||||||
|
http -A bearer -a "$API_TOKEN" :8080/api/v1/employees
|
||||||
|
```
|
||||||
|
|
||||||
|
**Get the vendor branches to copy an id to use for the purchase order**
|
||||||
|
|
||||||
|
```
|
||||||
|
http -A bearer -a "$API_TOKEN" :8080/api/v1/vendors/branches
|
||||||
|
```
|
||||||
|
|
||||||
|
**Generate first po**
|
||||||
|
|
||||||
|
```
|
||||||
|
http -A bearer -a "$API_TOKEN" :8080/api/v1/purchase-orders \
|
||||||
|
id:="60000" \
|
||||||
|
materials="Test" \
|
||||||
|
customer="Testy McTestface" \
|
||||||
|
createdForID="<employee-id>"
|
||||||
|
vendorBranchID="<vendor-branch-id>"
|
||||||
|
```
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// Represents an employee database model.
|
||||||
|
///
|
||||||
|
/// Employee's are who purchase orders can be generated for.
|
||||||
public struct Employee: Codable, Equatable, Identifiable, Sendable {
|
public struct Employee: Codable, Equatable, Identifiable, Sendable {
|
||||||
public var id: UUID
|
public var id: UUID
|
||||||
public var active: Bool
|
public var active: Bool
|
||||||
@@ -31,6 +34,8 @@ public struct Employee: Codable, Equatable, Identifiable, Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public extension Employee {
|
public extension Employee {
|
||||||
|
/// Represents the required fields for generating a new employee in the
|
||||||
|
/// database.
|
||||||
struct Create: Codable, Sendable, Equatable {
|
struct Create: Codable, Sendable, Equatable {
|
||||||
public let firstName: String
|
public let firstName: String
|
||||||
public let lastName: String
|
public let lastName: String
|
||||||
@@ -47,6 +52,8 @@ public extension Employee {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the required fields for updating an existing employee in the
|
||||||
|
/// database.
|
||||||
struct Update: Codable, Sendable, Equatable {
|
struct Update: Codable, Sendable, Equatable {
|
||||||
public let firstName: String?
|
public let firstName: String?
|
||||||
public let lastName: String?
|
public let lastName: String?
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// Represents a purchase order database model.
|
||||||
|
///
|
||||||
|
/// A purchase order is generated on behalf of an `Employee` and issued to
|
||||||
|
/// a `VendorBranch`. It includes information about the customer / job it was created
|
||||||
|
/// for, the materials that were purchased, etc.
|
||||||
public struct PurchaseOrder: Codable, Equatable, Identifiable, Sendable {
|
public struct PurchaseOrder: Codable, Equatable, Identifiable, Sendable {
|
||||||
|
|
||||||
public let id: Int
|
public let id: Int
|
||||||
@@ -41,6 +46,7 @@ public struct PurchaseOrder: Codable, Equatable, Identifiable, Sendable {
|
|||||||
|
|
||||||
public extension PurchaseOrder {
|
public extension PurchaseOrder {
|
||||||
|
|
||||||
|
/// Represents the required fields for generating a new purchase order in the database.
|
||||||
struct Create: Codable, Sendable, Equatable {
|
struct Create: Codable, Sendable, Equatable {
|
||||||
|
|
||||||
public let id: Int?
|
public let id: Int?
|
||||||
@@ -73,6 +79,9 @@ public extension PurchaseOrder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the required fields for generating a new purchase order in the database,
|
||||||
|
/// without the user information who is issuing the request, which get's parsed from the
|
||||||
|
/// currently authenticated user's session and is used to generate the full `Create` request.
|
||||||
struct CreateIntermediate: Codable, Sendable, Equatable {
|
struct CreateIntermediate: Codable, Sendable, Equatable {
|
||||||
|
|
||||||
public let id: Int?
|
public let id: Int?
|
||||||
@@ -115,6 +124,8 @@ public extension PurchaseOrder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the context to search or filter purchase orders based on the
|
||||||
|
/// given parameters.
|
||||||
enum SearchContext: Sendable, Equatable {
|
enum SearchContext: Sendable, Equatable {
|
||||||
case customer(String)
|
case customer(String)
|
||||||
case vendor(VendorBranch.ID)
|
case vendor(VendorBranch.ID)
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import Foundation
|
|||||||
|
|
||||||
public extension SiteRoute {
|
public extension SiteRoute {
|
||||||
|
|
||||||
|
/// Represents api routes that can be interacted with.
|
||||||
|
///
|
||||||
|
/// These routes return json information, as opposed to html like the view routes.
|
||||||
enum Api: Sendable, Equatable {
|
enum Api: Sendable, Equatable {
|
||||||
|
|
||||||
case employee(EmployeeRoute)
|
case employee(EmployeeRoute)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import CasePathsCore
|
|||||||
import Foundation
|
import Foundation
|
||||||
@preconcurrency import URLRouting
|
@preconcurrency import URLRouting
|
||||||
|
|
||||||
|
/// Represents all the routes that our server can handle.
|
||||||
public enum SiteRoute: Sendable {
|
public enum SiteRoute: Sendable {
|
||||||
case api(SiteRoute.Api)
|
case api(SiteRoute.Api)
|
||||||
case health
|
case health
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import Foundation
|
|||||||
|
|
||||||
public extension SiteRoute {
|
public extension SiteRoute {
|
||||||
// swiftlint:disable type_body_length
|
// swiftlint:disable type_body_length
|
||||||
|
|
||||||
|
/// Represents view routes that can be interacted with.
|
||||||
|
///
|
||||||
|
/// These routes return html and are used to generate the web interface.
|
||||||
enum View: Sendable, Equatable {
|
enum View: Sendable, Equatable {
|
||||||
|
|
||||||
case employee(SiteRoute.View.EmployeeRoute)
|
case employee(SiteRoute.View.EmployeeRoute)
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// Represents a user database model.
|
||||||
|
///
|
||||||
|
/// User's are who can login to the system and generate purchase orders, manage
|
||||||
|
/// employees, vendors, etc.
|
||||||
|
///
|
||||||
public struct User: Codable, Equatable, Identifiable, Sendable {
|
public struct User: Codable, Equatable, Identifiable, Sendable {
|
||||||
|
|
||||||
public var id: UUID
|
public var id: UUID
|
||||||
@@ -26,6 +31,7 @@ public struct User: Codable, Equatable, Identifiable, Sendable {
|
|||||||
|
|
||||||
public extension User {
|
public extension User {
|
||||||
|
|
||||||
|
/// Represents the fields needed to generate a new user in the database.
|
||||||
struct Create: Codable, Sendable, Equatable {
|
struct Create: Codable, Sendable, Equatable {
|
||||||
public let username: String
|
public let username: String
|
||||||
public let email: String
|
public let email: String
|
||||||
@@ -45,6 +51,7 @@ public extension User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the fields needed for new user to login.
|
||||||
struct Login: Codable, Sendable, Equatable {
|
struct Login: Codable, Sendable, Equatable {
|
||||||
public let username: String?
|
public let username: String?
|
||||||
public let email: String?
|
public let email: String?
|
||||||
@@ -61,6 +68,7 @@ public extension User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the fields needed to reset the password of a user.
|
||||||
struct ResetPassword: Codable, Equatable, Sendable {
|
struct ResetPassword: Codable, Equatable, Sendable {
|
||||||
public let password: String
|
public let password: String
|
||||||
public let confirmPassword: String
|
public let confirmPassword: String
|
||||||
@@ -74,6 +82,8 @@ public extension User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a user token that can be used to authenticate a user, typically
|
||||||
|
/// used for interacting with api routes remotely.
|
||||||
struct Token: Codable, Equatable, Identifiable, Sendable {
|
struct Token: Codable, Equatable, Identifiable, Sendable {
|
||||||
public let id: UUID
|
public let id: UUID
|
||||||
public let userID: User.ID
|
public let userID: User.ID
|
||||||
@@ -90,6 +100,7 @@ public extension User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the fields needed to update a user's attributes in the database.
|
||||||
struct Update: Codable, Equatable, Sendable {
|
struct Update: Codable, Equatable, Sendable {
|
||||||
public let username: String?
|
public let username: String?
|
||||||
public let email: String?
|
public let email: String?
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// Represents a vendor item in the database.
|
||||||
|
///
|
||||||
|
/// A vendor is parent item that contains one or more branches where purchase orders
|
||||||
|
/// can be issued to. It is primarily a name space to group related branches together.
|
||||||
public struct Vendor: Codable, Equatable, Identifiable, Sendable {
|
public struct Vendor: Codable, Equatable, Identifiable, Sendable {
|
||||||
public var id: UUID
|
public var id: UUID
|
||||||
public var name: String
|
public var name: String
|
||||||
@@ -25,6 +29,7 @@ public struct Vendor: Codable, Equatable, Identifiable, Sendable {
|
|||||||
|
|
||||||
public extension Vendor {
|
public extension Vendor {
|
||||||
|
|
||||||
|
/// Represents the fields required to generate a new vendor in the database.
|
||||||
struct Create: Codable, Sendable, Equatable {
|
struct Create: Codable, Sendable, Equatable {
|
||||||
public let name: String
|
public let name: String
|
||||||
|
|
||||||
@@ -33,6 +38,7 @@ public extension Vendor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the fields required to update a vendor in the database.
|
||||||
struct Update: Codable, Sendable, Equatable {
|
struct Update: Codable, Sendable, Equatable {
|
||||||
public let name: String
|
public let name: String
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// Represents a vendor branch database model.
|
||||||
|
///
|
||||||
|
/// A vendor branch is who purchase orders can be issued to on behalf an `Employee`.
|
||||||
|
/// They are associated with a particular `Vendor`.
|
||||||
public struct VendorBranch: Codable, Equatable, Identifiable, Sendable {
|
public struct VendorBranch: Codable, Equatable, Identifiable, Sendable {
|
||||||
public var id: UUID
|
public var id: UUID
|
||||||
public var name: String
|
public var name: String
|
||||||
@@ -24,6 +28,8 @@ public struct VendorBranch: Codable, Equatable, Identifiable, Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public extension VendorBranch {
|
public extension VendorBranch {
|
||||||
|
|
||||||
|
/// Represents the fields required to generate a new vendor branch in the database.
|
||||||
struct Create: Codable, Sendable, Equatable {
|
struct Create: Codable, Sendable, Equatable {
|
||||||
public let name: String
|
public let name: String
|
||||||
public let vendorID: Vendor.ID
|
public let vendorID: Vendor.ID
|
||||||
@@ -34,6 +40,10 @@ public extension VendorBranch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the details of a vendor branch, which includes the parent vendor item.
|
||||||
|
///
|
||||||
|
/// This is used in several of the views / api routes that require information about both the
|
||||||
|
/// vendor branch and it's associated parent vendor item.
|
||||||
struct Detail: Codable, Equatable, Identifiable, Sendable {
|
struct Detail: Codable, Equatable, Identifiable, Sendable {
|
||||||
public var id: UUID
|
public var id: UUID
|
||||||
public var name: String
|
public var name: String
|
||||||
@@ -56,6 +66,7 @@ public extension VendorBranch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the fields that are used to update attributes of a vendor branch in the database.
|
||||||
struct Update: Codable, Sendable, Equatable {
|
struct Update: Codable, Sendable, Equatable {
|
||||||
public let name: String?
|
public let name: String?
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ services:
|
|||||||
app:
|
app:
|
||||||
image: hhe-po:latest
|
image: hhe-po:latest
|
||||||
build:
|
build:
|
||||||
context: .
|
context: ..
|
||||||
|
dockerfile: ./docker/Dockerfile
|
||||||
environment:
|
environment:
|
||||||
<<: *shared_environment
|
<<: *shared_environment
|
||||||
volumes:
|
volumes:
|
||||||
@@ -30,12 +31,20 @@ services:
|
|||||||
- '8080:8080'
|
- '8080:8080'
|
||||||
labels:
|
labels:
|
||||||
- dev.orbstack.domains=po.local
|
- dev.orbstack.domains=po.local
|
||||||
|
healthcheck:
|
||||||
|
test: curl --fail -s http://0.0.0.0:8080/health || exit 1
|
||||||
|
interval: 1m30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
deploy:
|
||||||
|
replicas: 3
|
||||||
# user: '0' # uncomment to run as root for testing purposes even though Dockerfile defines 'vapor' user.
|
# user: '0' # uncomment to run as root for testing purposes even though Dockerfile defines 'vapor' user.
|
||||||
command: ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"]
|
command: ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"]
|
||||||
migrate:
|
migrate:
|
||||||
image: hhe-po:latest
|
image: hhe-po:latest
|
||||||
build:
|
build:
|
||||||
context: .
|
context: ..
|
||||||
|
dockerfile: ./docker/Dockerfile
|
||||||
environment:
|
environment:
|
||||||
<<: *shared_environment
|
<<: *shared_environment
|
||||||
command: ["migrate", "--yes"]
|
command: ["migrate", "--yes"]
|
||||||
@@ -46,7 +55,8 @@ services:
|
|||||||
revert:
|
revert:
|
||||||
image: hhe-po:latest
|
image: hhe-po:latest
|
||||||
build:
|
build:
|
||||||
context: .
|
context: ..
|
||||||
|
dockerfile: ./docker/Dockerfile
|
||||||
environment:
|
environment:
|
||||||
<<: *shared_environment
|
<<: *shared_environment
|
||||||
command: ["migrate", "--revert", "--yes"]
|
command: ["migrate", "--revert", "--yes"]
|
||||||
|
|||||||
Reference in New Issue
Block a user