Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
package pkg
import (
"context"
"fmt"
"github.com/julienschmidt/httprouter"
"html/template"
"math"
"net/http"
"time"
)
2024-08-21 01:36:12 +00:00
const (
PaymentTypePayment = "P"
PaymentTypeCollection = "C"
)
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
func servePaymentIndex ( w http . ResponseWriter , r * http . Request , _ httprouter . Params ) {
conn := getConn ( r )
2024-08-15 00:59:46 +00:00
company := mustGetCompany ( r )
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
locale := getLocale ( r )
2024-08-15 00:59:46 +00:00
page := NewPaymentIndexPage ( r . Context ( ) , conn , company , locale )
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
page . MustRender ( w , r )
}
2024-08-17 03:31:01 +00:00
func serveExpensePaymentIndex ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
expenseSlug := params [ 0 ] . Value
conn := getConn ( r )
company := mustGetCompany ( r )
locale := getLocale ( r )
expense := mustGetPaymentExpense ( r . Context ( ) , conn , expenseSlug )
if expense == nil {
http . NotFound ( w , r )
return
}
page := NewPaymentIndexPageForExpense ( r . Context ( ) , conn , company , locale , expense )
page . MustRender ( w , r )
}
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
type PaymentIndexPage struct {
Payments [ ] * PaymentEntry
2024-08-17 03:31:01 +00:00
BaseURI string
Expense * PaymentExpense
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
}
2024-08-15 00:59:46 +00:00
func NewPaymentIndexPage ( ctx context . Context , conn * Conn , company * Company , locale * Locale ) * PaymentIndexPage {
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
return & PaymentIndexPage {
2024-08-21 01:36:12 +00:00
Payments : mustCollectPaymentEntries ( ctx , conn , company , locale , "" , 0 ) ,
2024-08-17 03:31:01 +00:00
BaseURI : companyURI ( company , "/payments" ) ,
}
}
func NewPaymentIndexPageForExpense ( ctx context . Context , conn * Conn , company * Company , locale * Locale , expense * PaymentExpense ) * PaymentIndexPage {
return & PaymentIndexPage {
2024-08-21 01:36:12 +00:00
Payments : mustCollectPaymentEntries ( ctx , conn , company , locale , PaymentTypePayment , expense . Id ) ,
2024-08-17 03:31:01 +00:00
BaseURI : companyURI ( company , "/expenses/" + expense . Slug + "/payments" ) ,
Expense : expense ,
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
}
}
func ( page * PaymentIndexPage ) MustRender ( w http . ResponseWriter , r * http . Request ) {
mustRenderMainTemplate ( w , r , "payments/index.gohtml" , page )
}
2024-08-17 03:31:01 +00:00
type PaymentExpense struct {
Id int
Slug string
InvoiceNumber string
}
func mustGetPaymentExpense ( ctx context . Context , conn * Conn , expenseSlug string ) * PaymentExpense {
if ! ValidUuid ( expenseSlug ) {
return nil
}
expense := & PaymentExpense { }
if notFoundErrorOrPanic ( conn . QueryRow ( ctx , `
select expense_id
, slug
, coalesce ( nullif ( invoice_number , ' ' ) , slug : : text )
from expense
where expense . slug = $ 1
` , expenseSlug ) . Scan (
& expense . Id ,
& expense . Slug ,
& expense . InvoiceNumber ) ) {
return nil
}
return expense
}
func ( expense * PaymentExpense ) calcRemainingPaymentAmount ( ctx context . Context , conn * Conn ) string {
return conn . MustGetText ( ctx , "" , `
select to_price ( greatest ( 0 , expense . amount + tax_amount - paid_amount ) : : int , decimal_digits )
from (
select coalesce ( sum ( payment . amount ) , 0 ) as paid_amount
from expense_payment
join payment using ( payment_id )
where expense_payment . expense_id = $ 1
) as payment
cross join (
select coalesce ( sum ( amount ) , 0 ) as tax_amount
from expense_tax_amount
where expense_id = $ 1
) as tax
cross join (
select amount , decimal_digits
from expense
join currency using ( currency_code )
where expense_id = $ 1
) as expense
` , expense . Id )
}
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
type PaymentEntry struct {
2024-08-11 22:08:18 +00:00
ID int
2024-08-21 01:36:12 +00:00
Type string
2024-08-11 22:08:18 +00:00
Slug string
PaymentDate time . Time
Description string
2024-08-21 01:36:12 +00:00
DocumentSlug string
2024-08-15 01:59:30 +00:00
InvoiceNumber string
2024-08-11 22:08:18 +00:00
Total string
OriginalFileName string
Tags [ ] string
Status string
StatusLabel string
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
}
2024-08-21 01:36:12 +00:00
func mustCollectPaymentEntries ( ctx context . Context , conn * Conn , company * Company , locale * Locale , paymentType string , documentId int ) [ ] * PaymentEntry {
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
rows := conn . MustQuery ( ctx , `
2024-08-21 01:36:12 +00:00
select $ 5 as type
, payment_id
, payment . slug
, payment_date
, description
, to_price ( payment . amount , decimal_digits ) as total
, payment . tags
, payment . payment_status
, psi18n . name
, coalesce ( attachment . original_filename , ' ' )
, coalesce ( expense . slug : : text , ' ' )
, coalesce ( expense . invoice_number , ' ' )
from payment
join payment_status_i18n psi18n on payment . payment_status = psi18n . payment_status and psi18n . lang_tag = $ 1
join currency using ( currency_code )
left join payment_attachment as attachment using ( payment_id )
left join expense_payment using ( payment_id )
left join expense using ( expense_id )
where payment . company_id = $ 2
and ( $ 3 = ' ' or ( $ 3 = $ 5 and expense_id = $ 4 ) )
union all
select $ 6 as type
, collection_id
, collection . slug
, collection_date as payment_date
, description
, to_price ( collection . amount , decimal_digits ) as total
, collection . tags
, collection . payment_status
, psi18n . name
, coalesce ( attachment . original_filename , ' ' )
, coalesce ( invoice . slug : : text , ' ' )
, coalesce ( invoice . invoice_number , ' ' )
from collection
join payment_status_i18n psi18n on collection . payment_status = psi18n . payment_status and psi18n . lang_tag = $ 1
join currency using ( currency_code )
left join collection_attachment as attachment using ( collection_id )
left join invoice_collection using ( collection_id )
left join invoice using ( invoice_id )
where collection . company_id = $ 2
and ( $ 3 = ' ' or ( $ 3 = $ 6 and invoice_id = $ 4 ) )
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
order by payment_date desc , total desc
2024-08-21 01:36:12 +00:00
` , locale . Language , company . Id , paymentType , documentId , PaymentTypePayment , PaymentTypeCollection )
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
defer rows . Close ( )
var entries [ ] * PaymentEntry
for rows . Next ( ) {
entry := & PaymentEntry { }
2024-08-21 01:36:12 +00:00
if err := rows . Scan ( & entry . Type , & entry . ID , & entry . Slug , & entry . PaymentDate , & entry . Description , & entry . Total , & entry . Tags , & entry . Status , & entry . StatusLabel , & entry . OriginalFileName , & entry . DocumentSlug , & entry . InvoiceNumber ) ; err != nil {
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
panic ( err )
}
entries = append ( entries , entry )
}
if rows . Err ( ) != nil {
panic ( rows . Err ( ) )
}
return entries
}
func servePaymentForm ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
locale := getLocale ( r )
conn := getConn ( r )
company := mustGetCompany ( r )
form := newPaymentForm ( r . Context ( ) , conn , locale , company )
slug := params [ 0 ] . Value
if slug == "new" {
form . PaymentDate . Val = time . Now ( ) . Format ( "2006-01-02" )
form . MustRender ( w , r )
return
}
if ! ValidUuid ( slug ) {
http . NotFound ( w , r )
return
}
if ! form . MustFillFromDatabase ( r . Context ( ) , conn , slug ) {
http . NotFound ( w , r )
return
}
form . MustRender ( w , r )
}
2024-08-17 03:31:01 +00:00
func serveExpensePaymentForm ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
locale := getLocale ( r )
conn := getConn ( r )
company := mustGetCompany ( r )
expenseSlug := params [ 0 ] . Value
expense := mustGetPaymentExpense ( r . Context ( ) , conn , expenseSlug )
if expense == nil {
http . NotFound ( w , r )
return
}
form := newPaymentFormForExpense ( r . Context ( ) , conn , locale , company , expense )
paymentSlug := params [ 1 ] . Value
if paymentSlug == "new" {
form . PaymentDate . Val = time . Now ( ) . Format ( "2006-01-02" )
form . Description . Val = fmt . Sprintf ( gettext ( "Payment of %s" , locale ) , form . Expense . InvoiceNumber )
form . Amount . Val = form . Expense . calcRemainingPaymentAmount ( r . Context ( ) , conn )
form . MustRender ( w , r )
return
}
if ! ValidUuid ( paymentSlug ) {
http . NotFound ( w , r )
return
}
if ! form . MustFillFromDatabase ( r . Context ( ) , conn , paymentSlug ) {
http . NotFound ( w , r )
return
}
form . MustRender ( w , r )
}
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
type PaymentForm struct {
locale * Locale
company * Company
Slug string
2024-08-17 03:31:01 +00:00
BaseURI string
Expense * PaymentExpense
2024-08-21 01:36:12 +00:00
Type * SelectField
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
Description * InputField
PaymentDate * InputField
PaymentAccount * SelectField
Amount * InputField
2024-08-11 22:08:18 +00:00
File * FileField
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
Tags * TagsField
}
func newPaymentForm ( ctx context . Context , conn * Conn , locale * Locale , company * Company ) * PaymentForm {
return & PaymentForm {
locale : locale ,
company : company ,
2024-08-17 03:31:01 +00:00
BaseURI : companyURI ( company , "/payments" ) ,
2024-08-21 01:36:12 +00:00
Type : & SelectField {
Name : "type" ,
Label : pgettext ( "input" , "Type" , locale ) ,
Required : true ,
Options : [ ] * SelectOption {
{ Value : PaymentTypePayment , Label : pgettext ( "payment type" , "Payment" , locale ) } ,
{ Value : PaymentTypeCollection , Label : pgettext ( "payment type" , "Collection" , locale ) } ,
} ,
} ,
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
Description : & InputField {
Name : "description" ,
Label : pgettext ( "input" , "Description" , locale ) ,
Required : true ,
Type : "text" ,
} ,
PaymentDate : & InputField {
Name : "payment_date" ,
2024-08-15 23:58:59 +00:00
Label : pgettext ( "input" , "Payment Date" , locale ) ,
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
Required : true ,
Type : "date" ,
} ,
PaymentAccount : & SelectField {
Name : "payment_account" ,
Label : pgettext ( "input" , "Account" , locale ) ,
Required : true ,
2024-08-15 00:59:46 +00:00
Options : MustGetOptions ( ctx , conn , "select payment_account_id::text, name from payment_account where company_id = $1 order by name" , company . Id ) ,
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
} ,
Amount : & InputField {
Name : "amount" ,
Label : pgettext ( "input" , "Amount" , locale ) ,
Type : "number" ,
Required : true ,
Attributes : [ ] template . HTMLAttr {
` min="0" ` ,
template . HTMLAttr ( fmt . Sprintf ( ` step="%v" ` , company . MinCents ( ) ) ) ,
} ,
} ,
2024-08-11 22:08:18 +00:00
File : & FileField {
Name : "file" ,
Label : pgettext ( "input" , "File" , locale ) ,
MaxSize : 1 << 20 ,
} ,
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
Tags : & TagsField {
Name : "tags" ,
Label : pgettext ( "input" , "Tags" , locale ) ,
} ,
}
}
2024-08-17 03:31:01 +00:00
func newPaymentFormForExpense ( ctx context . Context , conn * Conn , locale * Locale , company * Company , expense * PaymentExpense ) * PaymentForm {
form := newPaymentForm ( ctx , conn , locale , company )
2024-08-21 01:36:12 +00:00
form . Type . Selected = [ ] string { PaymentTypePayment }
2024-08-17 03:31:01 +00:00
form . BaseURI = companyURI ( company , "/expenses/" + expense . Slug + "/payments" )
form . Expense = expense
return form
}
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
func ( f * PaymentForm ) MustRender ( w http . ResponseWriter , r * http . Request ) {
if f . Slug == "" {
2024-08-21 01:36:12 +00:00
f . Type . EmptyLabel = gettext ( "Select a type." , f . locale )
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
f . PaymentAccount . EmptyLabel = gettext ( "Select an account." , f . locale )
mustRenderMainTemplate ( w , r , "payments/new.gohtml" , f )
} else {
mustRenderMainTemplate ( w , r , "payments/edit.gohtml" , f )
}
}
func ( f * PaymentForm ) MustFillFromDatabase ( ctx context . Context , conn * Conn , slug string ) bool {
2024-08-21 01:36:12 +00:00
selectedType := f . Type . Selected
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
selectedPaymentAccount := f . PaymentAccount . Selected
f . PaymentAccount . Clear ( )
if notFoundErrorOrPanic ( conn . QueryRow ( ctx , `
2024-08-21 01:36:12 +00:00
select $ 2 as type
, description
, payment_date
, payment_account_id : : text
, to_price ( amount , decimal_digits )
, tags
from payment
join currency using ( currency_code )
where payment . slug = $ 1
union all
select $ 3 as type
, description
, collection_date
, payment_account_id : : text
, to_price ( amount , decimal_digits )
, tags
from collection
join currency using ( currency_code )
where collection . slug = $ 1
` , slug , PaymentTypePayment , PaymentTypeCollection ) . Scan (
f . Type ,
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
f . Description ,
f . PaymentDate ,
f . PaymentAccount ,
f . Amount ,
f . Tags ) ) {
2024-08-21 01:36:12 +00:00
f . Type . Selected = selectedType
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
f . PaymentAccount . Selected = selectedPaymentAccount
return false
}
f . Slug = slug
return true
}
func ( f * PaymentForm ) Parse ( r * http . Request ) error {
2024-08-11 22:08:18 +00:00
if err := r . ParseMultipartForm ( f . File . MaxSize ) ; err != nil {
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
return err
}
2024-08-21 01:36:12 +00:00
f . Type . FillValue ( r )
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
f . Description . FillValue ( r )
f . PaymentDate . FillValue ( r )
f . PaymentAccount . FillValue ( r )
f . Amount . FillValue ( r )
2024-08-11 22:08:18 +00:00
if err := f . File . FillValue ( r ) ; err != nil {
return err
}
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
f . Tags . FillValue ( r )
return nil
}
func ( f * PaymentForm ) Validate ( ) bool {
validator := newFormValidator ( )
2024-08-21 01:36:12 +00:00
validator . CheckValidSelectOption ( f . Type , gettext ( "Selected payment type is not valid." , f . locale ) )
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
validator . CheckRequiredInput ( f . Description , gettext ( "Description can not be empty." , f . locale ) )
validator . CheckValidSelectOption ( f . PaymentAccount , gettext ( "Selected payment account is not valid." , f . locale ) )
validator . CheckValidDate ( f . PaymentDate , gettext ( "Payment date must be a valid date." , f . locale ) )
if validator . CheckRequiredInput ( f . Amount , gettext ( "Amount can not be empty." , f . locale ) ) {
validator . CheckValidDecimal ( f . Amount , f . company . MinCents ( ) , math . MaxFloat64 , gettext ( "Amount must be a number greater than zero." , f . locale ) )
}
return validator . AllOK ( )
}
func handleAddPayment ( w http . ResponseWriter , r * http . Request , _ httprouter . Params ) {
locale := getLocale ( r )
conn := getConn ( r )
company := mustGetCompany ( r )
form := newPaymentForm ( r . Context ( ) , conn , locale , company )
2024-08-17 03:31:01 +00:00
handleAddPaymentForm ( w , r , conn , company , form )
}
func handleAddPaymentForm ( w http . ResponseWriter , r * http . Request , conn * Conn , company * Company , form * PaymentForm ) {
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
if err := form . Parse ( r ) ; err != nil {
http . Error ( w , err . Error ( ) , http . StatusBadRequest )
return
}
if err := verifyCsrfTokenValid ( r ) ; err != nil {
http . Error ( w , err . Error ( ) , http . StatusForbidden )
return
}
if ! form . Validate ( ) {
if ! IsHTMxRequest ( r ) {
w . WriteHeader ( http . StatusUnprocessableEntity )
}
form . MustRender ( w , r )
return
}
2024-08-21 01:36:12 +00:00
var documentId any
2024-08-17 03:31:01 +00:00
if form . Expense != nil {
2024-08-21 01:36:12 +00:00
documentId = form . Expense . Id
2024-08-17 03:31:01 +00:00
}
2024-08-21 01:36:12 +00:00
if form . Type . String ( ) == PaymentTypePayment {
slug := conn . MustGetText ( r . Context ( ) , "" , "select add_payment($1, $2, $3, $4, $5, $6, $7)" , company . Id , documentId , form . PaymentDate , form . PaymentAccount , form . Description , form . Amount , form . Tags )
if len ( form . File . Content ) > 0 {
conn . MustQuery ( r . Context ( ) , "select attach_to_payment($1, $2, $3, $4)" , slug , form . File . OriginalFileName , form . File . ContentType , form . File . Content )
}
} else {
slug := conn . MustGetText ( r . Context ( ) , "" , "select add_collection($1, $2, $3, $4, $5, $6, $7)" , company . Id , documentId , form . PaymentDate , form . PaymentAccount , form . Description , form . Amount , form . Tags )
if len ( form . File . Content ) > 0 {
conn . MustQuery ( r . Context ( ) , "select attach_to_collection($1, $2, $3, $4)" , slug , form . File . OriginalFileName , form . File . ContentType , form . File . Content )
}
2024-08-11 22:08:18 +00:00
}
2024-08-17 03:31:01 +00:00
htmxRedirect ( w , r , form . BaseURI )
}
func handleAddExpensePayment ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
expenseSlug := params [ 0 ] . Value
locale := getLocale ( r )
conn := getConn ( r )
company := mustGetCompany ( r )
expense := mustGetPaymentExpense ( r . Context ( ) , conn , expenseSlug )
if expense == nil {
http . NotFound ( w , r )
return
}
form := newPaymentFormForExpense ( r . Context ( ) , conn , locale , company , expense )
handleAddPaymentForm ( w , r , conn , company , form )
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
}
func handleEditPayment ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
conn := getConn ( r )
locale := getLocale ( r )
company := mustGetCompany ( r )
form := newPaymentForm ( r . Context ( ) , conn , locale , company )
form . Slug = params [ 0 ] . Value
2024-08-17 03:31:01 +00:00
handleEditPaymentForm ( w , r , conn , form )
}
func handleEditPaymentForm ( w http . ResponseWriter , r * http . Request , conn * Conn , form * PaymentForm ) {
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
if ! ValidUuid ( form . Slug ) {
http . NotFound ( w , r )
return
}
if err := form . Parse ( r ) ; err != nil {
http . Error ( w , err . Error ( ) , http . StatusBadRequest )
return
}
if err := verifyCsrfTokenValid ( r ) ; err != nil {
http . Error ( w , err . Error ( ) , http . StatusForbidden )
return
}
if ! form . Validate ( ) {
if ! IsHTMxRequest ( r ) {
w . WriteHeader ( http . StatusUnprocessableEntity )
}
form . MustRender ( w , r )
return
}
2024-08-21 01:36:12 +00:00
if form . Type . String ( ) == PaymentTypePayment {
if found := conn . MustGetText ( r . Context ( ) , "" , "select edit_payment($1, $2, $3, $4, $5, $6)" , form . Slug , form . PaymentDate , form . PaymentAccount , form . Description , form . Amount , form . Tags ) ; found == "" {
http . NotFound ( w , r )
return
}
if len ( form . File . Content ) > 0 {
conn . MustQuery ( r . Context ( ) , "select attach_to_payment($1, $2, $3, $4)" , form . Slug , form . File . OriginalFileName , form . File . ContentType , form . File . Content )
}
} else {
if found := conn . MustGetText ( r . Context ( ) , "" , "select edit_collection($1, $2, $3, $4, $5, $6)" , form . Slug , form . PaymentDate , form . PaymentAccount , form . Description , form . Amount , form . Tags ) ; found == "" {
http . NotFound ( w , r )
return
}
if len ( form . File . Content ) > 0 {
conn . MustQuery ( r . Context ( ) , "select attach_to_collection($1, $2, $3, $4)" , form . Slug , form . File . OriginalFileName , form . File . ContentType , form . File . Content )
}
2024-08-11 22:08:18 +00:00
}
2024-08-17 03:31:01 +00:00
htmxRedirect ( w , r , form . BaseURI )
}
func handleEditExpensePayment ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
conn := getConn ( r )
locale := getLocale ( r )
company := mustGetCompany ( r )
expenseSlug := params [ 0 ] . Value
expense := mustGetPaymentExpense ( r . Context ( ) , conn , expenseSlug )
if expense == nil {
http . NotFound ( w , r )
return
}
form := newPaymentFormForExpense ( r . Context ( ) , conn , locale , company , expense )
form . Slug = params [ 1 ] . Value
handleEditPaymentForm ( w , r , conn , form )
Add the payments section
This actually should be the “payments and receivables” section, however
this is quite a mouthful; a “receivable” is a payment made **to** you,
therefore “payments” is ok.
In fact, there is still no receivables in there, as they should be in
a separate relation, to constraint them to invoices instead of expenses.
It will be done in a separate commit.
Since this section will be, in a sense, sort of simplified accounting,
i needed to introduce the “payment account” concept. There is no way,
yet, for users to add them, because i have to revamp the “tax details”
section, but this commit started to grow too big already.
The same reasoning for the attachment payment slips as PDF to payment:
something i have to add, but not yet in this commit.
2024-08-10 02:34:07 +00:00
}
2024-08-11 01:22:37 +00:00
func handleRemovePayment ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
2024-08-17 03:31:01 +00:00
company := mustGetCompany ( r )
removePayment ( w , r , params [ 0 ] . Value , companyURI ( company , "/payments" ) )
}
func removePayment ( w http . ResponseWriter , r * http . Request , slug string , backURI string ) {
2024-08-11 01:22:37 +00:00
if ! ValidUuid ( slug ) {
http . NotFound ( w , r )
return
}
if err := verifyCsrfTokenValid ( r ) ; err != nil {
http . Error ( w , err . Error ( ) , http . StatusForbidden )
return
}
conn := getConn ( r )
2024-08-21 01:36:12 +00:00
conn . MustExec ( r . Context ( ) , "select remove_payment($1), remove_collection($1)" , slug )
2024-08-11 01:22:37 +00:00
2024-08-17 03:31:01 +00:00
htmxRedirect ( w , r , backURI )
}
func handleRemoveExpensePayment ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
conn := getConn ( r )
expenseSlug := params [ 0 ] . Value
expense := mustGetPaymentExpense ( r . Context ( ) , conn , expenseSlug )
if expense == nil {
http . NotFound ( w , r )
return
}
2024-08-11 01:22:37 +00:00
company := mustGetCompany ( r )
2024-08-17 03:31:01 +00:00
removePayment ( w , r , params [ 1 ] . Value , companyURI ( company , "/expenses/" + expense . Slug + "/payments" ) )
2024-08-11 01:22:37 +00:00
}
2024-08-11 22:08:18 +00:00
func servePaymentAttachment ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
serveAttachment ( w , r , params , `
2024-08-21 01:36:12 +00:00
select mime_type
, content
from payment
join payment_attachment using ( payment_id )
where slug = $ 1
union all
select mime_type
, content
from collection
join collection_attachment using ( collection_id )
where slug = $ 1
2024-08-11 22:08:18 +00:00
` )
}
2024-08-15 02:18:35 +00:00
func servePaymentTagsEditForm ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
2024-08-21 01:36:12 +00:00
serveTagsEditForm ( w , r , params , "/payments/" , "select tags from payment where slug = $1 union all select tags from collection where slug = $1" )
2024-08-15 02:18:35 +00:00
}
func handleUpdatePaymentTags ( w http . ResponseWriter , r * http . Request , params httprouter . Params ) {
2024-08-21 01:36:12 +00:00
handleUpdateTags ( w , r , params , "/payments/" , "with p as (update payment set tags = $1 where slug = $2 returning slug), c as (update collection set tags = $1 where slug = $2 returning slug) select p.slug from p union all select c.slug from c" )
2024-08-15 02:18:35 +00:00
}