Current section
Files
Jump to
Current section
Files
lib/invoicex/document/invoice.ex
defmodule Invoicex.Document.Invoice do
@moduledoc """
Stores invoice data.
"""
use Ecto.Schema
alias Ecto.Changeset
alias Invoicex.Document
alias Invoicex.Document.{Attachment, Buyer, Group, Item, Note, Number, Seller}
alias Invoicex.Ecommerce.Trader
alias Invoicex.Enum.{Currency, InvoiceStatus, InvoiceType}
alias Invoicex.Extra.Reason
@required_fields [:buyer_trader_id, :currency, :seller_trader_id, :status, :title, :type]
@fields [
:custom_number,
:description,
:due_date,
:expected_payment_date,
:footer,
:issue_date,
:pdf_path
] ++ @required_fields
@messages %{
empty: "Expected at least one group or item",
invalid: "Invalid order of group(s) and/or item(s)"
}
@schema_prefix Invoicex.schema_prefix()
schema "invoices" do
belongs_to(:buyer_trader, Trader)
belongs_to(:seller_trader, Trader)
embeds_many(:attachments, Attachment)
embeds_many(:correct_reasons, Reason, on_replace: :delete)
embeds_many(:edit_reasons, Reason, on_replace: :delete)
embeds_many(:groups, Group, on_replace: :delete)
embeds_many(:items, Item, on_replace: :delete)
embeds_many(:notes, Note, on_replace: :delete)
embeds_one(:buyer, Buyer, on_replace: :update)
embeds_one(:number, Number, on_replace: :update)
embeds_one(:seller, Seller, on_replace: :update)
field(:currency, Currency)
field(:custom_number, :string)
field(:description, :string)
field(:due_date, :date)
field(:expected_payment_date, :date)
field(:footer, :string)
field(:issue_date, :date)
field(:list, {:array, :map}, virtual: true)
field(:pdf_path, :string)
field(:status, InvoiceStatus, default: :draft)
field(:title, :string)
field(:total, :decimal, virtual: true)
field(:type, InvoiceType)
timestamps()
end
@doc false
def changeset(invoice \\ %__MODULE__{}, attrs \\ %{}) do
invoice
|> Changeset.cast(attrs, @fields)
|> Changeset.assoc_constraint(:buyer_trader)
|> Changeset.assoc_constraint(:seller_trader)
|> Changeset.cast_embed(:attachments)
|> Changeset.cast_embed(:buyer, required: true)
|> Changeset.cast_embed(:correct_reasons)
|> Changeset.cast_embed(:edit_reasons)
|> Changeset.cast_embed(:groups)
|> Changeset.cast_embed(:items)
|> Changeset.cast_embed(:notes)
|> Changeset.cast_embed(:seller, required: true)
|> custom_validates()
|> validate_number()
|> Changeset.validate_required(@required_fields)
end
defp custom_validates(changeset) do
list = Document.build_list(changeset)
Document.validate_orders(changeset, list, @messages)
end
defp validate_number(changeset) do
number = changeset.params["number"] || %{}
type = Changeset.get_field(changeset, :type)
number_type = if type == :pro_forma, do: :normal, else: type
is_key_atom = number |> Map.keys() |> List.first() |> is_atom()
param_key = if is_key_atom, do: :type, else: "type"
new_number = put_in(number, [param_key], number_type)
changeset
|> put_in([Access.key(:params), "number"], new_number)
|> Changeset.cast_embed(:number, required: true)
end
end