what am I doing wrong here? Decimal doesn’t’ seem to be working!
schema "purchase_order" do
embeds_many(:purchase_order_item, PurchaseOrderItem, on_replace: :delete)
field(:po_no, :integer, read_after_writes: true)
field(:tax, :float, read_after_writes: true)
field(:total, :decimal, read_after_writes: true)
field(:delivery_charges, :decimal, read_after_writes: true)
field(:approved, :boolean, read_after_writes: true)
field(:date_approved, :utc_datetime, read_after_writes: true)
belongs_to(:distribution_centre, DistributionCentre)
belongs_to(:supplier, Supplier)
timestamps(type: :utc_datetime, read_after_writes: true)
end
@doc false
def changeset(purchase_order, attrs) do
purchase_order
|> cast(attrs, [
:distribution_centre_id,
:supplier_id,
:approved,
:delivery_charges,
:po_no,
:tax,
:total,
:date_approved
])
|> cast_embed(:purchase_order_item, required: true, with: &PurchaseOrderItem.changeset/2)
|> set_total
|> validate_inclusion(:po_no, generate_po_code())
|> validate_required([:distribution_centre_id, :approved])
|> unique_constraint(:po_no, name: :purchase_order_po_no_index)
|> foreign_key_constraint(:distribution_centre_id)
|> foreign_key_constraint(:supplier_id, name: :purchase_order_supplier_id_fkey)
end
defp set_total(changeset) do
purchase_order_items = get_field(changeset, :purchase_order_item)
total =
Enum.reduce(purchase_order_items, Decimal.new(0), fn items, acc ->
taxes = get_field(changeset, :tax) |> Decimal.from_float()
delivery_charges = get_field(changeset, :delivery_charges)
tax_and_delivery = Decimal.add(taxes, delivery_charges)
Decimal.add(tax_and_delivery, Decimal.add(acc, items.total))
end)
changeset
|> put_change(:total, total)
end
defp generate_po_code(length \\ 10) do
code =
10
|> :math.pow(length)
|> round()
|> :rand.uniform()
|> Integer.to_string()
|> String.pad_leading(length, "0")
{:ok, code}
end
And this is the embedded schema.
embedded_schema do
field(:item_name, :string, read_after_writes: true)
field(:description, :string, read_after_writes: true)
field(:quantity, :integer, read_after_writes: true)
field(:unit_price, :decimal, read_after_writes: true)
field(:total, :decimal, read_after_writes: true)
field(:delete, :boolean, virtual: true)
timestamps(type: :utc_datetime, read_after_writes: true)
end
@doc false
def changeset(%PurchaseOrderItem{} = purchase_order_item, attrs) do
purchase_order_item
|> cast(attrs, [
:item_name,
:description,
:total,
:quantity,
:unit_price,
:delete
])
|> set_delete
|> set_total
|> validate_required([:item_name, :description, :quantity, :unit_price])
end
defp set_total(changeset) do
quantity = get_field(changeset, :quantity) |> Decimal.new()
unit_price = get_field(changeset, :unit_price)
quantity_and_price = Decimal.mult(quantity, unit_price)
changeset
|> put_change(:total, quantity_and_price)
end
defp set_delete(changeset) do
if get_change(changeset, :delete) do
%{changeset | action: :delete}
else
changeset
end
end