Class: Invoicing::LedgerItem::RenderUBL::UBLOutputBuilder
- Inherits:
-
Object
- Object
- Invoicing::LedgerItem::RenderUBL::UBLOutputBuilder
- Defined in:
- lib/invoicing/ledger_item/render_ubl.rb
Overview
:nodoc:
Constant Summary collapse
- UBL_NAMESPACES =
XML Namespaces required by UBL
{ "xmlns:cac" => "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2", "xmlns:cbc" => "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" }
- UBL_DOC_NAMESPACES =
{ :Invoice => "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2", :SelfBilledInvoice => "urn:oasis:names:specification:ubl:schema:xsd:SelfBilledInvoice-2", :CreditNote => "urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2", :SelfBilledCreditNote => "urn:oasis:names:specification:ubl:schema:xsd:SelfBilledCreditNote-2" }
Instance Attribute Summary collapse
-
#cached_values ⇒ Object
readonly
Returns the value of attribute cached_values.
-
#doc_type ⇒ Object
readonly
Returns the value of attribute doc_type.
-
#factor ⇒ Object
readonly
Returns the value of attribute factor.
-
#ledger_item ⇒ Object
readonly
Returns the value of attribute ledger_item.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
Instance Method Summary collapse
-
#build ⇒ Object
Returns a UBL XML rendering of the ledger item previously passed to the constructor.
-
#build_line_item(invoice_line, line_item) ⇒ Object
Given a
Builder::XmlMarkup
instance and aLineItem
instance, builds a UBL representation of that line item, something like the following:. -
#build_party(xml, details) ⇒ Object
Given a
Builder::XmlMarkup
instance and a supplier/customer details hash (as returned byLedgerItem#sender_details
andLedgerItem#recipient_details
, builds a UBL representation of that party, something like the following:. -
#build_period(xml, start_datetime, end_datetime) ⇒ Object
Given a
Builder::XmlMarkup
instance and two datetime objects, builds a UBL representation of the period between the two dates and times, something like the following:. -
#initialize(ledger_item, options) ⇒ UBLOutputBuilder
constructor
A new instance of UBLOutputBuilder.
-
#method_missing(method_id, *args, &block) ⇒ Object
For convenience while building the XML structure, method_missing redirects method calls to the ledger item (taking account of method renaming via acts_as_ledger_item options); calls to foo_of(line_item) are redirected to line_item.foo (taking account of method renaming via acts_as_line_item options).
Constructor Details
#initialize(ledger_item, options) ⇒ UBLOutputBuilder
Returns a new instance of UBLOutputBuilder.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 52 def initialize(ledger_item, ) @ledger_item = ledger_item @options = @cached_values = {} subtype = ledger_item.send(:ledger_item_class_info).subtype @doc_type = if [:invoice, :credit_note].include? subtype if total_amount >= BigDecimal('0') @factor = BigDecimal('1') sender_details.symbolize_keys[:is_self] ? :Invoice : :SelfBilledInvoice else @factor = BigDecimal('-1') sender_details.symbolize_keys[:is_self] ? :CreditNote : :SelfBilledCreditNote end else raise RuntimeError, "render_ubl not implemented for ledger item subtype #{subtype.inspect}" end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_id, *args, &block) ⇒ Object
For convenience while building the XML structure, method_missing redirects method calls to the ledger item (taking account of method renaming via acts_as_ledger_item options); calls to foo_of(line_item) are redirected to line_item.foo (taking account of method renaming via acts_as_line_item options).
75 76 77 78 79 80 81 82 83 84 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 75 def method_missing(method_id, *args, &block) method_id = method_id.to_sym if method_id.to_s =~ /^(.*)_of$/ method_id = $1.to_sym line_item = args[0] line_item.send(:line_item_class_info).get(line_item, method_id) else cached_values[method_id] ||= ledger_item.send(:ledger_item_class_info).get(ledger_item, method_id) end end |
Instance Attribute Details
#cached_values ⇒ Object (readonly)
Returns the value of attribute cached_values.
50 51 52 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 50 def cached_values @cached_values end |
#doc_type ⇒ Object (readonly)
Returns the value of attribute doc_type.
50 51 52 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 50 def doc_type @doc_type end |
#factor ⇒ Object (readonly)
Returns the value of attribute factor.
50 51 52 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 50 def factor @factor end |
#ledger_item ⇒ Object (readonly)
Returns the value of attribute ledger_item.
50 51 52 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 50 def ledger_item @ledger_item end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
50 51 52 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 50 def @options end |
Instance Method Details
#build ⇒ Object
Returns a UBL XML rendering of the ledger item previously passed to the constructor.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 87 def build ubl = Builder::XmlMarkup.new :indent => 4 ubl.instruct! :xml ubl.ubl doc_type, UBL_NAMESPACES.clone.update({'xmlns:ubl' => UBL_DOC_NAMESPACES[doc_type]}) do |invoice| invoice.cbc :ID, identifier invoice.cbc :UUID, uuid if uuid issue_date_formatted, issue_time_formatted = date_and_time(issue_date || Time.now) invoice.cbc :IssueDate, issue_date_formatted invoice.cbc :IssueTime, issue_time_formatted # Different document types have the child elements InvoiceTypeCode, Note and # TaxPointDate in a different order. WTF?! if doc_type == :Invoice invoice.cbc :InvoiceTypeCode, method_missing(:type) invoice.cbc :Note, description invoice.cbc :TaxPointDate, issue_date_formatted else invoice.cbc :TaxPointDate, issue_date_formatted invoice.cbc :InvoiceTypeCode, method_missing(:type) if doc_type == :SelfBilledInvoice invoice.cbc :Note, description end invoice.cac :InvoicePeriod do |invoice_period| build_period(invoice_period, period_start, period_end) end if period_start && period_end if [:Invoice, :CreditNote].include?(doc_type) invoice.cac :AccountingSupplierParty do |supplier| build_party supplier, sender_details end invoice.cac :AccountingCustomerParty do |customer| customer.cbc :SupplierAssignedAccountID, recipient_id build_party customer, recipient_details end elsif [:SelfBilledInvoice, :SelfBilledCreditNote].include?(doc_type) invoice.cac :AccountingCustomerParty do |customer| build_party customer, recipient_details end invoice.cac :AccountingSupplierParty do |supplier| supplier.cbc :CustomerAssignedAccountID, sender_id build_party supplier, sender_details end end invoice.cac :PaymentTerms do |payment_terms| payment_terms.cac :SettlementPeriod do |settlement_period| build_period(settlement_period, issue_date || Time.now, due_date) end end if due_date && [:Invoice, :SelfBilledInvoice].include?(doc_type) invoice.cac :TaxTotal do |tax_total| tax_total.cbc :TaxAmount, (factor*tax_amount).to_s, :currencyID => currency end if tax_amount invoice.cac :LegalMonetaryTotal do |monetary_total| monetary_total.cbc :TaxExclusiveAmount, (factor*(total_amount - tax_amount)).to_s, :currencyID => currency if tax_amount monetary_total.cbc :PayableAmount, (factor*total_amount).to_s, :currencyID => currency end line_items.sorted(:tax_point).each do |line_item| line_tag = if [:CreditNote, :SelfBilledCreditNote].include? doc_type :CreditNoteLine else :InvoiceLine end invoice.cac line_tag do |invoice_line| build_line_item(invoice_line, line_item) end end end ubl.target! end |
#build_line_item(invoice_line, line_item) ⇒ Object
Given a Builder::XmlMarkup
instance and a LineItem
instance, builds a UBL representation of that line item, something like the following:
<cbc:ID>123</cbc:ID>
<cbc:UUID>0cc659f0-cfac-012b-481d-0017f22d32c0</cbc:UUID>
<cbc:InvoicedQuantity>1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="GBP">123.45</cbc:LineExtensionAmount>
<cbc:TaxPointDate>2009-01-01</cbc:TaxPointDate>
<cac:TaxTotal><cbc:TaxAmount currencyID="GBP">12.34</cbc:TaxAmount></cac:TaxTotal>
<cac:Item><cbc:Description>Foo bar baz</cbc:Description></cac:Item>
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 246 def build_line_item(invoice_line, line_item) invoice_line.cbc :ID, id_of(line_item) invoice_line.cbc :UUID, uuid_of(line_item) if uuid_of(line_item) quantity_tag = [:Invoice, :SelfBilledInvoice].include?(doc_type) ? :InvoicedQuantity : :CreditedQuantity invoice_line.cbc quantity_tag, quantity_of(line_item) if quantity_of(line_item) invoice_line.cbc :LineExtensionAmount, (factor*net_amount_of(line_item)).to_s, :currencyID => currency if tax_point_of(line_item) tax_point_date, tax_point_time = date_and_time(tax_point_of(line_item)) invoice_line.cbc :TaxPointDate, tax_point_date end invoice_line.cac :TaxTotal do |tax_total| tax_total.cbc :TaxAmount, (factor*tax_amount_of(line_item)).to_s, :currencyID => currency end if tax_amount_of(line_item) invoice_line.cac :Item do |item| item.cbc :Description, description_of(line_item) #cac:BuyersItemIdentification #cac:SellersItemIdentification #cac:ClassifiedTaxCategory #cac:ItemInstance end #cac:Price end |
#build_party(xml, details) ⇒ Object
Given a Builder::XmlMarkup
instance and a supplier/customer details hash (as returned by LedgerItem#sender_details
and LedgerItem#recipient_details
, builds a UBL representation of that party, something like the following:
<cac:Party>
<cac:PartyName>
<cbc:Name>The Big Bank</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Paved With Gold Street</cbc:StreetName>
<cbc:CityName>London</cbc:CityName>
<cbc:PostalZone>E14 5HQ</cbc:PostalZone>
<cac:Country><cbc:IdentificationCode>GB</cbc:IdentificationCode></cac:Country>
</cac:PostalAddress>
</cac:Party>
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 202 def build_party(xml, details) details = details.symbolize_keys xml.cac :Party do |party| party.cac :PartyName do |party_name| party_name.cbc :Name, details[:name] end if details[:name] party.cac :PostalAddress do |postal_address| street1, street2 = details[:address].strip.split("\n", 2) postal_address.cbc :StreetName, street1 if street1 postal_address.cbc :AdditionalStreetName, street2 if street2 postal_address.cbc :CityName, details[:city] if details[:city] postal_address.cbc :PostalZone, details[:postal_code] if details[:postal_code] postal_address.cbc :CountrySubentity, details[:state] if details[:state] postal_address.cac :Country do |country| country.cbc :IdentificationCode, details[:country_code] if details[:country_code] country.cbc :Name, details[:country] if details[:country] end if details[:country_code] || details[:country] end party.cac :PartyTaxScheme do |party_tax_scheme| party_tax_scheme.cbc :CompanyID, details[:tax_number] party_tax_scheme.cac :TaxScheme do |tax_scheme| tax_scheme.cbc :ID, "VAT" # TODO: make country-dependent (e.g. GST in Australia) end end if details[:tax_number] party.cac :Contact do |contact| contact.cbc :Name, details[:contact_name] end if details[:contact_name] end end |
#build_period(xml, start_datetime, end_datetime) ⇒ Object
Given a Builder::XmlMarkup
instance and two datetime objects, builds a UBL representation of the period between the two dates and times, something like the following:
<cbc:StartDate>2008-05-06</cbc:StartTime>
<cbc:StartTime>12:34:56+02:00</cbc:StartTime>
<cbc:EndDate>2008-07-02</cbc:EndDate>
<cbc:EndTime>01:02:03+02:00</cbc:EndTime>
177 178 179 180 181 182 183 184 |
# File 'lib/invoicing/ledger_item/render_ubl.rb', line 177 def build_period(xml, start_datetime, end_datetime) start_date, start_time = date_and_time(start_datetime) end_date, end_time = date_and_time(end_datetime) xml.cbc :StartDate, start_date xml.cbc :StartTime, start_time xml.cbc :EndDate, end_date xml.cbc :EndTime, end_time end |