Skip to content

Commit

Permalink
Add sales receipts
Browse files Browse the repository at this point in the history
Sales receipts are invoices paid for on the spot.
  • Loading branch information
akadusei committed Aug 22, 2024
1 parent 828c35c commit 359b60a
Show file tree
Hide file tree
Showing 53 changed files with 1,118 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### Added
- Allow paying for a given invoice
- Add sales receipts (invoices paid for on the spot)
- Add `Api::DirectReceipts::Create` action
- Add `Api::DirectReceipts::Edit` action
- Add `Api::DirectReceipts::New` action
Expand Down
33 changes: 33 additions & 0 deletions docs/05-INVOICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,41 @@ See <https://en.wikipedia.org/wiki/Invoice>
end
```

```crystal
# ->>> src/operations/create_sales_receipt.cr
class CreateSalesReceipt < Invoice::SaveOperation
# ...
end
```

A sales receipt is an invoice paid for on the spot. This operation creates an invoice and a corresponding receipt, and marks the invoice as paid. It is available only if `Receipt` model exists. If there is no `Receipt` model but `Transaction` exists, `CreateDirectSalesReceipt` is used instead.

```crystal
# ->>> src/operations/update_sales_receipt.cr
class UpdateSalesReceipt < Invoice::SaveOperation
# ...
end
```

This operation is available only if `Receipt` model exists. If there is no `Receipt` model but `Transaction` exists, `UpdateDirectSalesReceipt` is used instead.

1. Set up actions:

```crystal
# ->>> src/actions/invoices/new.cr
class Invoices::New < BrowserAction
# ...
# Use `Bill::DirectReceipts::New` instead if invoices
# are paid for on the spot.
include Bill::Invoices::New
get "/invoices/new" do
# Use `CreateDirectReceipt` instead if invoices
# are paid for on the spot.
operation = CreateInvoice.new(
# Uncomment after setting up invoice items
#line_items: Array(Hash(String, String)).new
Expand Down Expand Up @@ -184,6 +209,9 @@ See <https://en.wikipedia.org/wiki/Invoice>
class Invoices::Create < BrowserAction
# ...
# Use `Bill::DirectReceipts::Create` instead if invoices
# are paid for on the spot.
include Bill::Invoices::Create
post "/invoices" do
Expand Down Expand Up @@ -211,9 +239,14 @@ See <https://en.wikipedia.org/wiki/Invoice>
class Invoices::Edit < BrowserAction
# ...
# Use `Bill::DirectReceipts::Edit` instead if invoices
# are paid for on the spot.
include Bill::Invoices::Edit
get "/invoices/:invoice_id/edit" do
# Use `UpdateDirectReceipt` instead if invoices
# are paid for on the spot.
operation = UpdateInvoice.new(
invoice,
# Uncomment after setting up invoice items
Expand Down
34 changes: 34 additions & 0 deletions spec/bill/actions/api/direct_sales_receipt/create_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require "../../../../spec_helper"

describe Bill::Api::DirectSalesReceipts::Create do
it "creates sales receipt" do
user = UserFactory.create

response = ApiClient.exec(
Api::DirectSalesReceipts::Create,
invoice: {
user_id: user.id,
description: "New invoice",
due_at: 3.days.from_now,
status: :open
},
line_items: [{
description: "Item 1",
quantity: 2,
price_mu: 0.12
}]
)

response.should send_json(200, message: "action.invoice.create.success")

# ameba:disable Performance/AnyInsteadOfEmpty
InvoiceQuery.new.is_paid.any?.should be_true

TransactionQuery.new
.user_id(user.id)
.type(:receipt)
.is_finalized
.none?
.should(be_false)
end
end
29 changes: 29 additions & 0 deletions spec/bill/actions/api/direct_sales_receipt/update_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require "../../../../spec_helper"

describe Bill::Api::DirectSalesReceipts::Update do
it "updates sales receipt" do
user = UserFactory.create

invoice = InvoiceFactory.create &.user_id(user.id)
.description("New invoice")
.status(:draft)

InvoiceItemFactory.create &.invoice_id(invoice.id)

response = ApiClient.exec(
Api::DirectSalesReceipts::Update.with(invoice_id: invoice.id),
invoice: {status: :open}
)

response.should send_json(200, message: "action.invoice.update.success")

invoice.reload.status.paid?.should be_true

TransactionQuery.new
.user_id(user.id)
.type(:receipt)
.is_finalized
.none?
.should(be_false)
end
end
28 changes: 28 additions & 0 deletions spec/bill/actions/api/sales_receipt/create_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require "../../../../spec_helper"

describe Bill::Api::SalesReceipts::Create do
it "creates sales receipt" do
response = ApiClient.exec(
Api::SalesReceipts::Create,
invoice: {
user_id: UserFactory.create.id,
description: "New invoice",
due_at: 3.days.from_now,
status: :open
},
line_items: [{
description: "Item 1",
quantity: 2,
price_mu: 0.12
}]
)

response.should send_json(200, message: "action.invoice.create.success")

# ameba:disable Performance/AnyInsteadOfEmpty
InvoiceQuery.new.is_paid.any?.should be_true

# ameba:disable Performance/AnyInsteadOfEmpty
ReceiptQuery.new.is_finalized.any?.should be_true
end
end
27 changes: 27 additions & 0 deletions spec/bill/actions/api/sales_receipt/update_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require "../../../../spec_helper"

describe Bill::Api::SalesReceipts::Update do
it "updates sales receipt" do
user = UserFactory.create

invoice = InvoiceFactory.create &.user_id(user.id)
.description("New invoice")
.status(:draft)

InvoiceItemFactory.create &.invoice_id(invoice.id)

ReceiptQuery.new.none?.should be_true

response = ApiClient.exec(
Api::SalesReceipts::Update.with(invoice_id: invoice.id),
invoice: {status: :open}
)

response.should send_json(200, message: "action.invoice.update.success")

invoice.reload.status.paid?.should be_true

# ameba:disable Performance/AnyInsteadOfEmpty
ReceiptQuery.new.is_finalized.any?.should be_true
end
end
34 changes: 34 additions & 0 deletions spec/bill/actions/direct_sales_receipts/create_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require "../../../spec_helper"

describe Bill::DirectSalesReceipts::Create do
it "creates direct sales receipt" do
user = UserFactory.create

response = ApiClient.exec(
DirectSalesReceipts::Create,
invoice: {
user_id: user.id,
description: "New invoice",
due_at: 3.days.from_now,
status: :open
},
line_items: [{
description: "Item 1",
quantity: 2,
price_mu: 0.12
}]
)

response.status.should eq(HTTP::Status::FOUND)

# ameba:disable Performance/AnyInsteadOfEmpty
InvoiceQuery.new.is_paid.any?.should be_true

TransactionQuery.new
.user_id(user.id)
.type(:receipt)
.is_finalized
.none?
.should(be_false)
end
end
14 changes: 14 additions & 0 deletions spec/bill/actions/direct_sales_receipts/edit_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require "../../../spec_helper"

describe Bill::DirectSalesReceipts::Edit do
it "renders edit page" do
user = UserFactory.create
invoice = InvoiceFactory.create &.user_id(user.id)

response = ApiClient.exec(DirectSalesReceipts::Edit.with(
invoice_id: invoice.id
))

response.body.should eq("DirectSalesReceipts::EditPage")
end
end
9 changes: 9 additions & 0 deletions spec/bill/actions/direct_sales_receipts/new_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require "../../../spec_helper"

describe Bill::DirectSalesReceipts::New do
it "renders new page" do
response = ApiClient.exec(DirectSalesReceipts::New)

response.body.should eq("DirectSalesReceipts::NewPage")
end
end
29 changes: 29 additions & 0 deletions spec/bill/actions/direct_sales_receipts/update_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require "../../../spec_helper"

describe Bill::DirectSalesReceipts::Update do
it "updates direct sales receipt" do
user = UserFactory.create

invoice = InvoiceFactory.create &.user_id(user.id)
.description("New invoice")
.status(:draft)

InvoiceItemFactory.create &.invoice_id(invoice.id)

response = ApiClient.exec(
DirectSalesReceipts::Update.with(invoice_id: invoice.id),
invoice: {status: :open}
)

response.status.should eq(HTTP::Status::FOUND)

invoice.reload.status.paid?.should be_true

TransactionQuery.new
.user_id(user.id)
.type(:receipt)
.is_finalized
.none?
.should(be_false)
end
end
28 changes: 28 additions & 0 deletions spec/bill/actions/sales_receipts/create_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require "../../../spec_helper"

describe Bill::SalesReceipts::Create do
it "creates sales receipt" do
response = ApiClient.exec(
SalesReceipts::Create,
invoice: {
user_id: UserFactory.create.id,
description: "New invoice",
due_at: 3.days.from_now,
status: :open
},
line_items: [{
description: "Item 1",
quantity: 2,
price_mu: 0.12
}]
)

response.status.should eq(HTTP::Status::FOUND)

# ameba:disable Performance/AnyInsteadOfEmpty
InvoiceQuery.new.is_paid.any?.should be_true

# ameba:disable Performance/AnyInsteadOfEmpty
ReceiptQuery.new.is_finalized.any?.should be_true
end
end
12 changes: 12 additions & 0 deletions spec/bill/actions/sales_receipts/edit_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require "../../../spec_helper"

describe Bill::SalesReceipts::Edit do
it "renders edit page" do
user = UserFactory.create
invoice = InvoiceFactory.create &.user_id(user.id)

response = ApiClient.exec(SalesReceipts::Edit.with(invoice_id: invoice.id))

response.body.should eq("SalesReceipts::EditPage")
end
end
9 changes: 9 additions & 0 deletions spec/bill/actions/sales_receipts/new_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require "../../../spec_helper"

describe Bill::SalesReceipts::New do
it "renders new page" do
response = ApiClient.exec(SalesReceipts::New)

response.body.should eq("SalesReceipts::NewPage")
end
end
27 changes: 27 additions & 0 deletions spec/bill/actions/sales_receipts/update_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require "../../../spec_helper"

describe Bill::SalesReceipts::Update do
it "updates sales receipt" do
user = UserFactory.create

invoice = InvoiceFactory.create &.user_id(user.id)
.description("New invoice")
.status(:draft)

InvoiceItemFactory.create &.invoice_id(invoice.id)

ReceiptQuery.new.none?.should be_true

response = ApiClient.exec(
SalesReceipts::Update.with(invoice_id: invoice.id),
invoice: {status: :open}
)

response.status.should eq(HTTP::Status::FOUND)

invoice.reload.status.paid?.should be_true

# ameba:disable Performance/AnyInsteadOfEmpty
ReceiptQuery.new.is_finalized.any?.should be_true
end
end
Loading

0 comments on commit 359b60a

Please sign in to comment.