Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tech/update receipt update to use command #214

Merged
merged 14 commits into from
Apr 11, 2024
21 changes: 20 additions & 1 deletion internal/commands/bulk_status_update_command.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
package commands

import "receipt-wrangler/api/internal/models"
import (
"encoding/json"
"net/http"
"receipt-wrangler/api/internal/models"
"receipt-wrangler/api/internal/utils"
)

type BulkStatusUpdateCommand struct {
Comment string
Status models.ReceiptStatus
ReceiptIds []uint
}

func (command *BulkStatusUpdateCommand) LoadDataFromRequest(w http.ResponseWriter, r *http.Request) error {
bytes, err := utils.GetBodyData(w, r)
if err != nil {
return err
}

err = json.Unmarshal(bytes, &command)
if err != nil {
return err
}

return nil
}
13 changes: 13 additions & 0 deletions internal/commands/paged_request_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ type ReceiptPagedRequestCommand struct {
Filter ReceiptPagedRequestFilter `json:"filter"`
}

func (command *ReceiptPagedRequestCommand) LoadDataFromRequest(w http.ResponseWriter, r *http.Request) error {
bytes, err := utils.GetBodyData(w, r)
if err != nil {
return err
}

err = json.Unmarshal(bytes, &command)
if err != nil {
return err
}
return nil
}

type ReceiptPagedRequestFilter struct {
Date PagedRequestField `json:"date"`
Amount PagedRequestField `json:"amount"`
Expand Down
40 changes: 40 additions & 0 deletions internal/commands/upsert_category_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package commands

import (
"encoding/json"
"net/http"
"receipt-wrangler/api/internal/structs"
"receipt-wrangler/api/internal/utils"
)

type UpsertCategoryCommand struct {
Id *uint `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
}

func (category *UpsertCategoryCommand) LoadDataFromRequest(w http.ResponseWriter, r *http.Request) error {
bytes, err := utils.GetBodyData(w, r)
if err != nil {
return err
}

err = json.Unmarshal(bytes, &category)
if err != nil {
return err
}

return nil
}

func (category *UpsertCategoryCommand) Validate() structs.ValidatorError {
errors := make(map[string]string)
vErr := structs.ValidatorError{}

if len(category.Name) == 0 {
errors["name"] = "Name is required"
}

vErr.Errors = errors
return vErr
}
37 changes: 37 additions & 0 deletions internal/commands/upsert_comment_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package commands

import (
"receipt-wrangler/api/internal/structs"
)

type UpsertCommentCommand struct {
Comment string `json:"comment"`
ReceiptId uint `json:"receiptId"`
UserId uint `json:"userId"`
}

func (comment *UpsertCommentCommand) Validate(userRequestId uint, isCreate bool) structs.ValidatorError {
errors := make(map[string]string)
vErr := structs.ValidatorError{}

if len(comment.Comment) == 0 {
errors["comment"] = "Comment is required"
}

if !isCreate {
if comment.ReceiptId == 0 {
errors["receiptId"] = "Receipt Id is required"
}
}

if comment.UserId == 0 {
errors["userId"] = "User Id is required"
}

if comment.UserId != userRequestId {
errors["userId"] = "Bad user id"
}

vErr.Errors = errors
return vErr
}
54 changes: 54 additions & 0 deletions internal/commands/upsert_item_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package commands

import (
"github.com/shopspring/decimal"
"receipt-wrangler/api/internal/models"
"receipt-wrangler/api/internal/structs"
)

type UpsertItemCommand struct {
Amount decimal.Decimal `json:"amount"`
ChargedToUserId uint `json:"chargedToUserId"`
IsTaxed bool `json:"isTaxed"`
Name string `json:"name"`
ReceiptId uint `json:"receiptId"`
Status models.ItemStatus `json:"status"`
}

func (item *UpsertItemCommand) Validate(receiptAmount decimal.Decimal, isCreate bool) structs.ValidatorError {
errors := make(map[string]string)
vErr := structs.ValidatorError{}

if item.Amount.IsZero() {
errors["amount"] = "Amount is required"
}

if item.Amount.GreaterThan(receiptAmount) {
errors["amount"] = "Amount cannot be greater than receipt amount"
}

if item.Amount.LessThanOrEqual(decimal.Zero) {
errors["amount"] = "Amount must be greater than zero"
}

if len(item.Name) == 0 {
errors["name"] = "Name is required"
}

if !isCreate {
if item.ReceiptId == 0 {
errors["receiptId"] = "Receipt Id is required"
}
}

if item.ChargedToUserId == 0 {
errors["chargedToUserId"] = "Charged To User Id is required"
}

if len(item.Status) == 0 {
errors["status"] = "Status is required"
}

vErr.Errors = errors
return vErr
}
123 changes: 123 additions & 0 deletions internal/commands/upsert_receipt_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package commands

import (
"encoding/json"
"fmt"
"github.com/shopspring/decimal"
"net/http"
"receipt-wrangler/api/internal/models"
"receipt-wrangler/api/internal/structs"
"receipt-wrangler/api/internal/utils"
"time"
)

type UpsertReceiptCommand struct {
Name string `json:"name"`
Amount decimal.Decimal `json:"amount"`
Date time.Time `json:"date"`
GroupId uint `json:"groupId"`
PaidByUserID uint `json:"paidByUserId"`
Status models.ReceiptStatus `json:"status"`
Categories []UpsertCategoryCommand `json:"categories"`
Tags []UpsertTagCommand `json:"tags"`
Items []UpsertItemCommand `json:"receiptItems"`
Comments []UpsertCommentCommand `json:"comments"`
CreatedByString string `json:"createdByString"`
}

func (receipt *UpsertReceiptCommand) LoadDataFromRequest(w http.ResponseWriter, r *http.Request) error {
bytes, err := utils.GetBodyData(w, r)
if err != nil {
return err
}

err = json.Unmarshal(bytes, &receipt)
if err != nil {
return err
}

return nil
}

func (receipt *UpsertReceiptCommand) Validate(tokenUserId uint, isCreate bool) structs.ValidatorError {
errors := make(map[string]string)
vErr := structs.ValidatorError{}

if len(receipt.Name) == 0 {
errors["name"] = "Name is required"
}

if receipt.Amount.IsZero() {
errors["amount"] = "Amount is required"
}

if receipt.Amount.LessThanOrEqual(decimal.Zero) {
errors["amount"] = "Amount must be greater than zero"
}

if receipt.Date.IsZero() {
errors["date"] = "Date is required"
}

if receipt.GroupId == 0 {
errors["groupId"] = "Group Id is required"
}

if receipt.PaidByUserID == 0 {
errors["paidByUserId"] = "Paid By User Id is required"
}

if receipt.Status == "" {
errors["status"] = "Status is required"
}

for i, category := range receipt.Categories {
basePath := "categories." + fmt.Sprintf("%d", i)
categoryErrors := category.Validate()
for key, value := range categoryErrors.Errors {
errors[basePath+"."+key] = value
}
}

for i, tag := range receipt.Tags {
basePath := "tags." + fmt.Sprintf("%d", i)
tagErrors := tag.Validate()
for key, value := range tagErrors.Errors {
errors[basePath+"."+key] = value
}
}

for i, item := range receipt.Items {
basePath := "receiptItems." + fmt.Sprintf("%d", i)
itemErrors := item.Validate(receipt.Amount, isCreate)
for key, value := range itemErrors.Errors {
errors[basePath+"."+key] = value
}
}

for i, comment := range receipt.Comments {
basePath := "comments." + fmt.Sprintf("%d", i)
commentErrors := comment.Validate(tokenUserId, isCreate)
for key, value := range commentErrors.Errors {
errors[basePath+"."+key] = value
}
}

vErr.Errors = errors
return vErr
}

func (receipt *UpsertReceiptCommand) ToReceipt() (models.Receipt, error) {
var result models.Receipt
bytes, err := json.Marshal(receipt)
if err != nil {
return result, err
}

err = json.Unmarshal(bytes, &result)
if err != nil {
return result, err
}

return result, nil
}
14 changes: 14 additions & 0 deletions internal/commands/upsert_tag_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package commands
import (
"encoding/json"
"net/http"
"receipt-wrangler/api/internal/structs"
"receipt-wrangler/api/internal/utils"
)

type UpsertTagCommand struct {
Id *uint `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
}
Expand All @@ -24,3 +26,15 @@ func (tag *UpsertTagCommand) LoadDataFromRequest(w http.ResponseWriter, r *http.

return nil
}

func (tag *UpsertTagCommand) Validate() structs.ValidatorError {
errors := make(map[string]string)
vErr := structs.ValidatorError{}

if len(tag.Name) == 0 {
errors["name"] = "Name is required"
}

vErr.Errors = errors
return vErr
}
12 changes: 6 additions & 6 deletions internal/email/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func processEmails(emailMetadata []structs.EmailMetadata, groupSettings []models
return err
}

receipt, err := services.ReadReceiptImageFromFileOnly(imageForOcrPath)
command, err := services.ReadReceiptImageFromFileOnly(imageForOcrPath)
if err != nil {
return err
}
Expand All @@ -168,12 +168,12 @@ func processEmails(emailMetadata []structs.EmailMetadata, groupSettings []models
return fmt.Errorf("could not find group settings with id %d", groupSettingsId)
}

receipt.GroupId = groupSettingsToUse.GroupId
receipt.Status = groupSettingsToUse.EmailDefaultReceiptStatus
receipt.PaidByUserID = *groupSettingsToUse.EmailDefaultReceiptPaidById
receipt.CreatedByString = "Email Integration"
command.GroupId = groupSettingsToUse.GroupId
command.Status = groupSettingsToUse.EmailDefaultReceiptStatus
command.PaidByUserID = *groupSettingsToUse.EmailDefaultReceiptPaidById
command.CreatedByString = "Email Integration"

createdReceipt, err := receiptRepository.CreateReceipt(receipt, 0)
createdReceipt, err := receiptRepository.CreateReceipt(command, 0)
if err != nil {
return err
}
Expand Down
8 changes: 4 additions & 4 deletions internal/handlers/receipt_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,15 +203,15 @@ func MagicFillFromImage(w http.ResponseWriter, r *http.Request) {
ResponseType: constants.APPLICATION_JSON,
HandlerFunction: func(w http.ResponseWriter, r *http.Request) (int, error) {
receiptImageId := r.URL.Query().Get("receiptImageId")
filledReceipt := models.Receipt{}
receiptCommand := commands.UpsertReceiptCommand{}

if len(receiptImageId) > 0 {
errCode, err := validateReceiptImageAccess(r, models.VIEWER, receiptImageId)
if err != nil {
return errCode, err
}

filledReceipt, err = services.ReadReceiptImage(receiptImageId)
receiptCommand, err = services.ReadReceiptImage(receiptImageId)
if err != nil {
return http.StatusInternalServerError, err
}
Expand All @@ -238,13 +238,13 @@ func MagicFillFromImage(w http.ResponseWriter, r *http.Request) {
Filename: fileHeader.Filename,
}

filledReceipt, err = services.MagicFillFromImage(magicFillCommand)
receiptCommand, err = services.MagicFillFromImage(magicFillCommand)
if err != nil {
return http.StatusInternalServerError, err
}
}

bytes, err := utils.MarshalResponseData(filledReceipt)
bytes, err := utils.MarshalResponseData(receiptCommand)
if err != nil {
return http.StatusInternalServerError, err
}
Expand Down