defmodule Requests.Payments.Payment do @moduledoc """ TODO: either implement all of the sources or none and return the api errors. """ alias Customers.BillingAddress alias Customers.Phone alias Requests.Payments.Payment.{ AirlineData, AmountAllocation, BillingDescriptor, Risk, Sender } alias Requests.Payments.Sources alias Requests.Payments.ThreeDS @derive Jason.Encoder @type customer :: %{ id: String.t(), email: String.t(), name: String.t(), tax_number: String.t(), phone: Phone.t() } @type item :: %{ name: String.t(), quantity: String.t(), unit_price: String.t(), reference: String.t(), commodity_code: String.t(), unit_of_measure: String.t(), total_amount: String.t(), tax_amount: String.t(), discount_amount: String.t(), wxpay_goods_id: String.t(), url: String.t(), image_url: String.t() } @type processing :: %{ order_id: String.t(), tax_amount: integer(), discount_amount: integer(), duty_amount: integer(), shipping_amount: integer(), shipping_tax_amount: integer(), aft: true | false, preferred_scheme: String.t(), merchant_initiated_reason: String.t(), campaign_id: integer(), product_type: String.t(), open_id: String.t(), original_order_amount: integer(), receipt_id: String.t(), terminal_type: String.t(), os_type: String.t(), invoice_id: String.t(), brand_name: String.t(), locale: String.t(), shipping_preference: String.t(), user_action: String.t(), set_transaction_context: map(), airline_data: AirlineData.t(), purchase_country: String.t(), custom_payment_method_ids: list(String.t()), merchant_callback_url: String.t() } @type recipient :: %{ dob: String.t(), account_number: String.t(), address: BillingAddress.t(), first_name: String.t(), last_name: String.t() } @type shipping :: %{ address: BillingAddress.t(), phone: Phone.t(), from_address_zip: String.t() } @type t() :: %__MODULE__{ source: map(), amount: integer(), currency: <<_::3>>, payment_type: String.t(), merchant_initiated: true | false, reference: String.t(), description: String.t(), authorization_type: String.t(), capture: true | false, capture_on: String.t(), customer: customer(), billing_descriptor: BillingDescriptor.t(), shipping: shipping(), three_d_s: Integrated.t() | StandAlone.t() | ThirdParty.t(), processing_channel_id: String.t(), previous_payment_id: String.t(), risk: Risk.t(), success_url: String.t(), failure_url: String.t(), payment_ip: String.t(), sender: Sender.t(), recipient: recipient(), amount_allocations: list(AmountAllocation.t()), processing: processing(), items: list(item()), metadata: map(), type: String.t() } @enforce_keys [:currency, :processing_channel_id, :source, :type] defstruct [ :source, :amount, :currency, :payment_type, :merchant_initiated, :reference, :description, :authorization_type, :capture, :capture_on, :customer, :billing_descriptor, :shipping, :three_d_s, :"3ds", :processing_channel_id, :previous_payment_id, :risk, :success_url, :failure_url, :payment_ip, :sender, :recipient, :amount_allocations, :processing, :items, :metadata, :type ] def build( %{ currency: currency, source: source } = params ) when is_binary(currency) and is_map(source) do %__MODULE__{ source: Sources.build(source), amount: params[:amount], currency: currency, payment_type: params[:payment_type], merchant_initiated: params[:merchant_initiated], reference: params[:reference], description: params[:description], authorization_type: params[:authorization_type], capture: params[:capture], capture_on: params[:capture_on], customer: build_customer(params[:customer]), billing_descriptor: BillingDescriptor.build(params[:billing_descriptor]), shipping: build_shipping(params[:shipping]), "3ds": ThreeDS.build(params[:three_d_s]), processing_channel_id: params[:processing_channel_id], previous_payment_id: params[:previous_payment_id], risk: Risk.build(params[:risk]), success_url: params[:success_url], failure_url: params[:failure_url], payment_ip: params[:payment_ip], sender: Sender.build(params[:sender]), recipient: build_recipient(params[:recipient]), amount_allocations: AmountAllocation.build(params[:amount_allocations]), processing: build_processing(params[:processing]), items: build_items(params[:items]), metadata: params[:metadata], type: params[:type] } end def build(params) when is_map(params), do: {:error, "Payment must have currency, processing_channel_id, and source"} def build(_), do: {:error, "params must be a map"} defp build_customer(params) when is_map(params) do %{ id: params[:id], email: params[:email], name: params[:name], tax_number: params[:tax_number], phone: Phone.build(params[:phone]) } end defp build_customer(_), do: nil defp build_items(items) when is_list(items) do Enum.into(items, [], &build_item(&1)) end defp build_items(_), do: nil defp build_item(params) when is_map(params) do %{ name: params[:name], quantity: params[:quantity], unit_price: params[:unit_price], reference: params[:reference], commodity_code: params[:commodity_code], unit_of_measure: params[:unit_of_measure], total_amount: params[:total_amount], tax_amount: params[:tax_amount], discount_amount: params[:discount_amount], wxpay_goods_id: params[:wxpay_goods_id], url: params[:url], image_url: params[:image_url] } end defp build_item(_), do: nil defp build_processing(params) when is_map(params) do %{ order_id: params[:order_id], tax_amount: params[:tax_amount], discount_amount: params[:discount_amount], duty_amount: params[:duty_amount], shipping_amount: params[:shipping_amount], shipping_tax_amount: params[:shipping_tax_amount], aft: params[:aft], preferred_scheme: params[:preferred_scheme], merchant_initiated_reason: params[:merchant_initiated_reason], campaign_id: params[:campaign_id], product_type: params[:product_type], open_id: params[:open_id], original_order_amount: params[:original_order_amount], receipt_id: params[:receipt_id], terminal_type: params[:terminal_type], os_type: params[:os_type], invoice_id: params[:invoice_id], brand_name: params[:brand_name], locale: params[:locale], shipping_preference: params[:shipping_preference], user_action: params[:user_action], set_transaction_context: params[:set_transaction_context], airline_data: AirlineData.build(params[:airline_data]), purchase_country: params[:purchase_country], custom_payment_method_ids: params[:custom_payment_method_ids], merchant_callback_url: params[:merchant_callback_url] } end defp build_processing(_), do: nil defp build_recipient(params) when is_map(params) do %{ dob: params[:dob], account_number: params[:account_number], address: BillingAddress.build(params[:address]), first_name: params[:first_name], last_name: params[:last_name] } end defp build_recipient(_), do: nil defp build_shipping(params) when is_map(params) do %{ address: BillingAddress.build(params[:address]), phone: Phone.build(params[:phone]), from_address_zip: params[:from_address_zip] } end defp build_shipping(_), do: nil end