zatca 0.1.2 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -2
  3. data/bin/console +0 -0
  4. data/bin/setup +0 -0
  5. data/lib/zatca/client.rb +173 -0
  6. data/lib/zatca/hacks.rb +45 -0
  7. data/lib/zatca/hashing.rb +18 -0
  8. data/lib/zatca/qr_code_extractor.rb +31 -0
  9. data/lib/zatca/qr_code_generator.rb +9 -2
  10. data/lib/zatca/signing/certificate.rb +78 -0
  11. data/lib/zatca/signing/csr.rb +220 -0
  12. data/lib/zatca/signing/ecdsa.rb +59 -0
  13. data/lib/zatca/tag.rb +18 -8
  14. data/lib/zatca/tags.rb +5 -1
  15. data/lib/zatca/tags_schema.rb +5 -5
  16. data/lib/zatca/types.rb +7 -0
  17. data/lib/zatca/ubl/base_component.rb +142 -0
  18. data/lib/zatca/ubl/builder.rb +166 -0
  19. data/lib/zatca/ubl/common_aggregate_components/allowance_charge.rb +64 -0
  20. data/lib/zatca/ubl/common_aggregate_components/classified_tax_category.rb +25 -0
  21. data/lib/zatca/ubl/common_aggregate_components/delivery.rb +27 -0
  22. data/lib/zatca/ubl/common_aggregate_components/invoice_line.rb +63 -0
  23. data/lib/zatca/ubl/common_aggregate_components/item.rb +21 -0
  24. data/lib/zatca/ubl/common_aggregate_components/legal_monetary_total.rb +59 -0
  25. data/lib/zatca/ubl/common_aggregate_components/party.rb +28 -0
  26. data/lib/zatca/ubl/common_aggregate_components/party_identification.rb +25 -0
  27. data/lib/zatca/ubl/common_aggregate_components/party_legal_entity.rb +19 -0
  28. data/lib/zatca/ubl/common_aggregate_components/party_tax_scheme.rb +30 -0
  29. data/lib/zatca/ubl/common_aggregate_components/postal_address.rb +59 -0
  30. data/lib/zatca/ubl/common_aggregate_components/price.rb +20 -0
  31. data/lib/zatca/ubl/common_aggregate_components/tax_category.rb +56 -0
  32. data/lib/zatca/ubl/common_aggregate_components/tax_total.rb +58 -0
  33. data/lib/zatca/ubl/common_aggregate_components.rb +2 -0
  34. data/lib/zatca/ubl/invoice.rb +481 -0
  35. data/lib/zatca/ubl/invoice_subtype_builder.rb +50 -0
  36. data/lib/zatca/ubl/signing/cert.rb +48 -0
  37. data/lib/zatca/ubl/signing/invoice_signed_data_reference.rb +44 -0
  38. data/lib/zatca/ubl/signing/key_info.rb +25 -0
  39. data/lib/zatca/ubl/signing/object.rb +20 -0
  40. data/lib/zatca/ubl/signing/qualifying_properties.rb +27 -0
  41. data/lib/zatca/ubl/signing/signature.rb +50 -0
  42. data/lib/zatca/ubl/signing/signature_information.rb +19 -0
  43. data/lib/zatca/ubl/signing/signature_properties_reference.rb +26 -0
  44. data/lib/zatca/ubl/signing/signed_info.rb +21 -0
  45. data/lib/zatca/ubl/signing/signed_properties.rb +81 -0
  46. data/lib/zatca/ubl/signing/signed_signature_properties.rb +23 -0
  47. data/lib/zatca/ubl/signing/ubl_document_signatures.rb +25 -0
  48. data/lib/zatca/ubl/signing/ubl_extension.rb +22 -0
  49. data/lib/zatca/ubl/signing/ubl_extensions.rb +17 -0
  50. data/lib/zatca/ubl/signing.rb +2 -0
  51. data/lib/zatca/ubl.rb +2 -0
  52. data/lib/zatca/version.rb +1 -1
  53. data/lib/zatca.rb +27 -3
  54. data/zatca.gemspec +52 -0
  55. metadata +165 -10
  56. data/Gemfile.lock +0 -100
@@ -0,0 +1,59 @@
1
+ class ZATCA::UBL::CommonAggregateComponents::LegalMonetaryTotal < ZATCA::UBL::BaseComponent
2
+ attr_reader :line_extension_amount, :tax_exclusive_amount,
3
+ :tax_inclusive_amount, :allowance_total_amount, :prepaid_amount,
4
+ :payable_amount, :currency_id
5
+
6
+ # <cac:LegalMonetaryTotal>
7
+ # <cbc:LineExtensionAmount currencyID="SAR">966.00</cbc:LineExtensionAmount>
8
+ # <cbc:TaxExclusiveAmount currencyID="SAR">964.00</cbc:TaxExclusiveAmount>
9
+ # <cbc:TaxInclusiveAmount currencyID="SAR">1108.90</cbc:TaxInclusiveAmount>
10
+ # <cbc:AllowanceTotalAmount currencyID="SAR">2.00</cbc:AllowanceTotalAmount>
11
+ # <cbc:PrepaidAmount currencyID="SAR">0.00</cbc:PrepaidAmount>
12
+ # <cbc:PayableAmount currencyID="SAR">1108.90</cbc:PayableAmount>
13
+ # </cac:LegalMonetaryTotal>
14
+
15
+ def initialize(
16
+ line_extension_amount:,
17
+ tax_exclusive_amount:,
18
+ tax_inclusive_amount:,
19
+ allowance_total_amount:,
20
+ prepaid_amount: nil,
21
+ payable_amount: nil,
22
+ currency_id: "SAR"
23
+ )
24
+ @line_extension_amount = line_extension_amount
25
+ @tax_exclusive_amount = tax_exclusive_amount
26
+ @tax_inclusive_amount = tax_inclusive_amount
27
+ @allowance_total_amount = allowance_total_amount
28
+ @prepaid_amount = prepaid_amount
29
+ @payable_amount = payable_amount
30
+ @currency_id = currency_id
31
+ end
32
+
33
+ def name
34
+ "cac:LegalMonetaryTotal"
35
+ end
36
+
37
+ def prepaid_amount_element
38
+ return nil if @prepaid_amount.blank?
39
+
40
+ ZATCA::UBL::BaseComponent.new(name: "cbc:PrepaidAmount", value: @prepaid_amount, attributes: {"currencyID" => @currency_id})
41
+ end
42
+
43
+ def payable_amount_element
44
+ return nil if @payable_amount.blank?
45
+
46
+ ZATCA::UBL::BaseComponent.new(name: "cbc:PayableAmount", value: @payable_amount, attributes: {"currencyID" => @currency_id})
47
+ end
48
+
49
+ def elements
50
+ [
51
+ ZATCA::UBL::BaseComponent.new(name: "cbc:LineExtensionAmount", value: @line_extension_amount, attributes: {"currencyID" => @currency_id}),
52
+ ZATCA::UBL::BaseComponent.new(name: "cbc:TaxExclusiveAmount", value: @tax_exclusive_amount, attributes: {"currencyID" => @currency_id}),
53
+ ZATCA::UBL::BaseComponent.new(name: "cbc:TaxInclusiveAmount", value: @tax_inclusive_amount, attributes: {"currencyID" => @currency_id}),
54
+ ZATCA::UBL::BaseComponent.new(name: "cbc:AllowanceTotalAmount", value: @allowance_total_amount, attributes: {"currencyID" => @currency_id}),
55
+ prepaid_amount_element,
56
+ payable_amount_element
57
+ ]
58
+ end
59
+ end
@@ -0,0 +1,28 @@
1
+ class ZATCA::UBL::CommonAggregateComponents::Party < ZATCA::UBL::BaseComponent
2
+ # Has:
3
+ # PartyIdentification
4
+ # PostalAddress
5
+ # PartyTaxScheme
6
+ # PartyLegalEntity
7
+ def initialize(party_identification:, postal_address:, party_tax_scheme:, party_legal_entity:)
8
+ super()
9
+
10
+ @party_identification = party_identification
11
+ @postal_address = postal_address
12
+ @party_tax_scheme = party_tax_scheme
13
+ @party_legal_entity = party_legal_entity
14
+ end
15
+
16
+ def name
17
+ "cac:Party"
18
+ end
19
+
20
+ def elements
21
+ [
22
+ @party_identification,
23
+ @postal_address,
24
+ @party_tax_scheme,
25
+ @party_legal_entity
26
+ ]
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ class ZATCA::UBL::CommonAggregateComponents::PartyIdentification < ZATCA::UBL::BaseComponent
2
+ attr_reader :scheme_id, :id
3
+
4
+ SCHEMA = Dry::Schema.Params do
5
+ required(:id).filled(:string)
6
+ required(:scheme_id).filled(:string)
7
+ end
8
+
9
+ def initialize(id:, scheme_id: "CRN")
10
+ super()
11
+
12
+ @id = id
13
+ @scheme_id = scheme_id
14
+ end
15
+
16
+ def name
17
+ "cac:PartyIdentification"
18
+ end
19
+
20
+ def elements
21
+ [
22
+ ZATCA::UBL::BaseComponent.new(name: "cbc:ID", value: @id, attributes: {"schemeID" => @scheme_id})
23
+ ]
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ class ZATCA::UBL::CommonAggregateComponents::PartyLegalEntity < ZATCA::UBL::BaseComponent
2
+ attr_reader :scheme_id, :id
3
+
4
+ def initialize(registration_name:)
5
+ super()
6
+
7
+ @registration_name = registration_name
8
+ end
9
+
10
+ def name
11
+ "cac:PartyLegalEntity"
12
+ end
13
+
14
+ def elements
15
+ [
16
+ ZATCA::UBL::BaseComponent.build(name: "cbc:RegistrationName", value: @registration_name)
17
+ ]
18
+ end
19
+ end
@@ -0,0 +1,30 @@
1
+ class ZATCA::UBL::CommonAggregateComponents::PartyTaxScheme < ZATCA::UBL::BaseComponent
2
+ def initialize(
3
+ company_id: nil,
4
+ tax_scheme_id: "VAT"
5
+ )
6
+ super()
7
+
8
+ @company_id = company_id
9
+ @tax_scheme_id = tax_scheme_id
10
+ end
11
+
12
+ def name
13
+ "cac:PartyTaxScheme"
14
+ end
15
+
16
+ def company_id_element
17
+ return nil if @company_id.blank?
18
+
19
+ ZATCA::UBL::BaseComponent.new(name: "cbc:CompanyID", value: @company_id)
20
+ end
21
+
22
+ def elements
23
+ [
24
+ company_id_element,
25
+ ZATCA::UBL::BaseComponent.new(name: "cac:TaxScheme", elements: [
26
+ ZATCA::UBL::BaseComponent.new(name: "cbc:ID", value: @tax_scheme_id)
27
+ ])
28
+ ]
29
+ end
30
+ end
@@ -0,0 +1,59 @@
1
+ class ZATCA::UBL::CommonAggregateComponents::PostalAddress < ZATCA::UBL::BaseComponent
2
+ attr_accessor :street_name,
3
+ :additional_street_name,
4
+ :building_number,
5
+ :plot_identification,
6
+ :city_subdivision_name,
7
+ :city_name,
8
+ :postal_zone,
9
+ :country_subentity,
10
+ :country
11
+
12
+ SCHEMA = Dry::Schema.Params do
13
+ required(:street_name).filled(:string)
14
+ required(:additional_street_name).filled(:string)
15
+ required(:building_number).filled(:string)
16
+ required(:plot_identification).filled(:string)
17
+ required(:city_subdivision_name).filled(:string)
18
+ required(:city_name).filled(:string)
19
+ required(:postal_zone).filled(:string)
20
+ required(:country_subentity).filled(:string)
21
+ required(:country_identification_code).filled(:string)
22
+ end
23
+
24
+ def initialize(
25
+ street_name:, building_number:, plot_identification:,
26
+ city_subdivision_name:, city_name:, postal_zone:, country_subentity:,
27
+ additional_street_name: nil, country_identification_code: "SA"
28
+ )
29
+ @street_name = street_name
30
+ @additional_street_name = additional_street_name
31
+ @building_number = building_number
32
+ @plot_identification = plot_identification
33
+ @city_subdivision_name = city_subdivision_name
34
+ @city_name = city_name
35
+ @postal_zone = postal_zone
36
+ @country_subentity = country_subentity
37
+ @country_identification_code = country_identification_code
38
+ end
39
+
40
+ def name
41
+ "cac:PostalAddress"
42
+ end
43
+
44
+ def elements
45
+ [
46
+ ZATCA::UBL::BaseComponent.build(name: "cbc:StreetName", value: @street_name),
47
+ ZATCA::UBL::BaseComponent.build(name: "cbc:AdditionalStreetName", value: @additional_street_name),
48
+ ZATCA::UBL::BaseComponent.build(name: "cbc:BuildingNumber", value: @building_number),
49
+ ZATCA::UBL::BaseComponent.build(name: "cbc:PlotIdentification", value: @plot_identification),
50
+ ZATCA::UBL::BaseComponent.build(name: "cbc:CitySubdivisionName", value: @city_subdivision_name),
51
+ ZATCA::UBL::BaseComponent.build(name: "cbc:CityName", value: @city_name),
52
+ ZATCA::UBL::BaseComponent.build(name: "cbc:PostalZone", value: @postal_zone),
53
+ ZATCA::UBL::BaseComponent.build(name: "cbc:CountrySubentity", value: @country_subentity),
54
+ ZATCA::UBL::BaseComponent.build(name: "cac:Country", elements: [
55
+ ZATCA::UBL::BaseComponent.build(name: "cbc:IdentificationCode", value: @country_identification_code)
56
+ ])
57
+ ]
58
+ end
59
+ end
@@ -0,0 +1,20 @@
1
+ class ZATCA::UBL::CommonAggregateComponents::Price < ZATCA::UBL::BaseComponent
2
+ def initialize(price_amount:, allowance_charge: nil, currency_id: "SAR")
3
+ super()
4
+
5
+ @price_amount = price_amount
6
+ @allowance_charge = allowance_charge
7
+ @currency_id = currency_id
8
+ end
9
+
10
+ def name
11
+ "cac:Price"
12
+ end
13
+
14
+ def elements
15
+ [
16
+ ZATCA::UBL::BaseComponent.new(name: "cbc:PriceAmount", value: @price_amount, attributes: {currencyID: @currency_id}),
17
+ @allowance_charge
18
+ ]
19
+ end
20
+ end
@@ -0,0 +1,56 @@
1
+ class ZATCA::UBL::CommonAggregateComponents::TaxCategory < ZATCA::UBL::BaseComponent
2
+ attr_reader :id, :percent
3
+
4
+ # <cac:TaxCategory>
5
+ # <cbc:ID schemeAgencyID="6" schemeID="UN/ECE 5305">S</cbc:ID>
6
+ # <cbc:Percent>15.00</cbc:Percent>
7
+ # <cac:TaxScheme>
8
+ # <cbc:ID schemeAgencyID="6" schemeID="UN/ECE 5153">VAT</cbc:ID>
9
+ # </cac:TaxScheme>
10
+ # </cac:TaxCategory>
11
+ # <cac:TaxCategory>
12
+ # <cbc:ID>O</cbc:ID>
13
+ # <cbc:TaxExemptionReasonCode>VATEX-EU-O</cbc:TaxExemptionReasonCode>
14
+ # <cac:TaxScheme>
15
+ # <cbc:ID>VAT</cbc:ID>
16
+ # </cac:TaxScheme>
17
+ # </cac:TaxCategory>
18
+ def initialize(
19
+ tax_percent: "15.00", id: "S", scheme_agency_id: "6",
20
+ scheme_id: "UN/ECE 5305", tax_scheme_id: "VAT",
21
+ tax_scheme_scheme_id: "UN/ECE 5153", tax_exemption_reason_code: nil
22
+ )
23
+ super()
24
+
25
+ @tax_percent = tax_percent
26
+ @id = id
27
+ @scheme_agency_id = scheme_agency_id
28
+ @scheme_id = scheme_id
29
+ @tax_scheme_id = tax_scheme_id
30
+ @tax_scheme_scheme_id = tax_scheme_scheme_id
31
+ @tax_exemption_reason_code = tax_exemption_reason_code
32
+ end
33
+
34
+ def name
35
+ "cac:TaxCategory"
36
+ end
37
+
38
+ def elements
39
+ [
40
+ ZATCA::UBL::BaseComponent.new(name: "cbc:ID", value: @id, attributes: {"schemeAgencyID" => @scheme_agency_id, "schemeID" => @scheme_id}.compact),
41
+ tax_exemption_reason_code_element,
42
+ ZATCA::UBL::BaseComponent.new(name: "cbc:Percent", value: @tax_percent),
43
+ ZATCA::UBL::BaseComponent.new(name: "cac:TaxScheme", elements: [
44
+ ZATCA::UBL::BaseComponent.new(name: "cbc:ID", value: @tax_scheme_id, attributes: {"schemeAgencyID" => @scheme_agency_id, "schemeID" => @tax_scheme_scheme_id}.compact)
45
+ ])
46
+ ]
47
+ end
48
+
49
+ private
50
+
51
+ def tax_exemption_reason_code_element
52
+ if @tax_exemption_reason_code.present?
53
+ ZATCA::UBL::BaseComponent.new(name: "cbc:TaxExemptionReasonCode", value: @tax_exemption_reason_code)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,58 @@
1
+ class ZATCA::UBL::CommonAggregateComponents::TaxTotal < ZATCA::UBL::BaseComponent
2
+ # <cac:TaxTotal>
3
+ # <cbc:TaxAmount currencyID="SAR">144.9</cbc:TaxAmount>
4
+ # <cac:TaxSubtotal>
5
+ # <cbc:TaxableAmount currencyID="SAR">966.00</cbc:TaxableAmount>
6
+ # <cbc:TaxAmount currencyID="SAR">144.90</cbc:TaxAmount>
7
+ # <cac:TaxCategory>
8
+ # <cbc:ID schemeAgencyID="6" schemeID="UN/ECE 5305">S</cbc:ID>
9
+ # <cbc:Percent>15.00</cbc:Percent>
10
+ # <cac:TaxScheme>
11
+ # <cbc:ID schemeAgencyID="6" schemeID="UN/ECE 5153">VAT</cbc:ID>
12
+ # </cac:TaxScheme>
13
+ # </cac:TaxCategory>
14
+ # </cac:TaxSubtotal>
15
+ # </cac:TaxTotal>
16
+
17
+ def initialize(
18
+ tax_amount:, tax_subtotal_amount: nil, taxable_amount: nil,
19
+ rounding_amount: nil, tax_category: nil, currency_id: "SAR"
20
+ )
21
+ super()
22
+
23
+ @tax_amount = tax_amount
24
+ @tax_subtotal_amount = tax_subtotal_amount
25
+ @taxable_amount = taxable_amount
26
+ @rounding_amount = rounding_amount
27
+ @tax_category = tax_category || ZATCA::UBL::CommonAggregateComponents::TaxCategory.new
28
+ @currency_id = currency_id
29
+ end
30
+
31
+ def name
32
+ "cac:TaxTotal"
33
+ end
34
+
35
+ def tax_subtotal_element
36
+ if @taxable_amount.present? && @tax_subtotal_amount.present? && @tax_category.present?
37
+ ZATCA::UBL::BaseComponent.new(name: "cac:TaxSubtotal", elements: [
38
+ ZATCA::UBL::BaseComponent.new(name: "cbc:TaxableAmount", value: @taxable_amount, attributes: {"currencyID" => @currency_id}),
39
+ ZATCA::UBL::BaseComponent.new(name: "cbc:TaxAmount", value: @tax_subtotal_amount, attributes: {"currencyID" => @currency_id}),
40
+ @tax_category
41
+ ])
42
+ end
43
+ end
44
+
45
+ def rounding_amount_element
46
+ if @rounding_amount.present?
47
+ ZATCA::UBL::BaseComponent.new(name: "cbc:RoundingAmount", value: @rounding_amount, attributes: {"currencyID" => @currency_id})
48
+ end
49
+ end
50
+
51
+ def elements
52
+ [
53
+ ZATCA::UBL::BaseComponent.new(name: "cbc:TaxAmount", value: @tax_amount, attributes: {"currencyID" => @currency_id}),
54
+ rounding_amount_element,
55
+ tax_subtotal_element
56
+ ]
57
+ end
58
+ end
@@ -0,0 +1,2 @@
1
+ module ZATCA::UBL::CommonAggregateComponents
2
+ end