uae-gold-calculator 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a7d280f92d142e15ab21616135e1ca094a384cbcf3503a4ca9f4d63ed62e7704
4
+ data.tar.gz: 3c443bccbe540f53e87067b0421150222a492b437b5d92ec35226f439b1f1d7d
5
+ SHA512:
6
+ metadata.gz: 0576f2eb658146d1700e9eb393957cef924c85250d2ed5f3187b49a45f3705f3d24c1bf175571704e37ed29a423a98decd09da7a8b0d379498acd175ab786a45
7
+ data.tar.gz: b052de66bce06d27c3544e3fd65c7f279481cca3fe67bc7a7c8f99bcc576e6e53526a82653e5940bcec6a0fc2e410844aadd24f8ee29fe5745bc47a9a25a4c1f
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 UAE Gold Prices (https://uaegoldprices.ae/)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # uae-gold-calculator
2
+
3
+ Gold value calculator for the UAE market. Give it today's 24K price per gram and it works out every karat, any weight unit, the making charge, 5% VAT and zakat, in Arabic or English. No network calls, no dependencies.
4
+
5
+ - **Karat table**: 24K, 22K, 21K, 18K and 14K per gram, per tola and per troy ounce using the fineness UAE price boards quote: 24K 999, 22K 914, 21K 874, 18K 749, 14K 583 (karat price = 24K price × fineness ÷ 999).
6
+ - **Units**: gram, kilogram, troy ounce (31.1034768 g), tola (11.6638038 g) and mithqal (4.25 g). Arabic unit names such as `جرام`, `أونصة`, `تولة`, `مثقال` work too.
7
+ - **Jewellery price**: metal value + making charge (AED per gram, percent of metal, or a fixed amount) + VAT on both, the way UAE shops bill it.
8
+ - **Zakat**: adds up pure gold across items, compares it with the 85 g nisab and returns 2.5% of the value when due.
9
+ - **Friendly input**: `461.11`, `461,11`, `14,342.21` and Arabic-Indic `٤٦١٫١١` all parse.
10
+ - **Arabic and English** CLI output (`--lang ar`).
11
+
12
+ ## Install
13
+
14
+ ```
15
+ gem install uae-gold-calculator
16
+ ```
17
+
18
+ ## Library
19
+
20
+ ```ruby
21
+ require "uae_gold_calculator"
22
+ G = UaeGoldCalculator
23
+
24
+ G.price_table(461.11)[2][:per_gram] # => 403.41 (21K)
25
+ G.item_price(price24: 461.11, weight: 10, karat: 21, making: 30)[:total] # => 4550.84
26
+ G.zakat(461.11, [{ weight: 100, karat: 21 }])[:zakat] # => 1008.53
27
+ G.parse_number("٤٦١٫١١") # => 461.11
28
+ ```
29
+
30
+ ## CLI
31
+
32
+ ```
33
+ $ uae-gold-calculator table --price 461.11
34
+ Karat Per gram Per tola Per ounce
35
+ 24K (999) 461.11 5378.30 14342.12
36
+ 22K (914) 421.88 4920.68 13121.82
37
+ 21K (874) 403.41 4705.34 12547.56
38
+ 18K (749) 345.72 4032.38 10753.00
39
+ 14K (583) 269.10 3138.69 8369.83
40
+
41
+ $ uae-gold-calculator item --price 461.11 --weight 10 --karat 21 --making 30 --lang ar
42
+ قيمة الذهب: 4034.14 د.إ
43
+ المصنعية: 300.00 د.إ
44
+ ضريبة القيمة المضافة (5%): 216.71 د.إ
45
+ الإجمالي: 4550.84 د.إ
46
+
47
+ $ uae-gold-calculator convert 2 tola g
48
+ 23.3276
49
+
50
+ $ uae-gold-calculator zakat --price 461.11 --weight 100 --karat 21
51
+ Zakat due: 1008.53 AED
52
+ ```
53
+
54
+ Options for `item`: `--unit g|kg|oz|tola|mithqal`, `--karat`, `--making`, `--making-type per_gram|percent|fixed`, `--vat 0.05` (use `--vat 0` for investment bars, which are zero-rated in the UAE).
55
+
56
+ ## How it calculates
57
+
58
+ | Step | Formula |
59
+ |---|---|
60
+ | Karat price per gram | `price24 × fineness / 999` (24K 999, 22K 914, 21K 874, 18K 749, 16K 666, 14K 583; other karats `karat / 24`) |
61
+ | Metal value | `grams × karat price` |
62
+ | Making charge | `rate × grams`, or `metal × rate / 100`, or a fixed amount |
63
+ | VAT | `(metal + making) × 5%` |
64
+ | Zakat | `24K-equivalent grams = Σ grams × purity`; due when ≥ 85 g; `2.5% × pure grams × price24` |
65
+
66
+ Amounts are rounded half away from zero to 2 decimals on output only. Results are estimates: shop prices, VAT treatment of investment gold and zakat rulings vary, so check with your jeweller or scholar.
67
+
68
+ ## بالعربية
69
+
70
+ حاسبة لقيمة الذهب في الإمارات: أدخل سعر جرام الذهب عيار 24 اليوم لتحصل على أسعار عيارات 24 و22 و21 و18 و14 بالجرام والتولة والأونصة، وسعر قطعة المجوهرات مع المصنعية وضريبة القيمة المضافة 5%، وحساب زكاة الذهب حسب نصاب 85 جرامًا. تقبل الأرقام العربية مثل ٤٦١٫١١ وأسماء الوحدات بالعربية، وتعمل دون اتصال بالإنترنت.
71
+
72
+ ## Links
73
+
74
+ - Live UAE gold rates: [سعر الذهب اليوم في الامارات](https://uaegoldprices.ae/)
75
+ - Source code: https://github.com/nbkdevs/uae-gold-prices
76
+
77
+ ## License
78
+
79
+ MIT © UAE Gold Prices
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "uae_gold_calculator"
5
+
6
+ G = UaeGoldCalculator
7
+ pos = []
8
+ opt = {}
9
+ i = 0
10
+ while i < ARGV.length
11
+ if ARGV[i].start_with?("--")
12
+ opt[ARGV[i][2..]] = ARGV[i + 1]
13
+ i += 2
14
+ else
15
+ pos << ARGV[i]
16
+ i += 1
17
+ end
18
+ end
19
+ ar = opt["lang"] == "ar"
20
+ cur = ar ? "د.إ" : "AED"
21
+ begin
22
+ case pos.first
23
+ when "convert"
24
+ puts G.round_money(G.convert(pos[1], pos[2], pos[3]), 4)
25
+ when "table"
26
+ puts(ar ? "العيار\tسعر الجرام\tسعر التولة\tسعر الأونصة" : "Karat\tPer gram\tPer tola\tPer ounce")
27
+ G.price_table(opt.fetch("price")).each do |r|
28
+ puts format("%dK (%d)\t%.2f\t%.2f\t%.2f", r[:karat], r[:hallmark], r[:per_gram], r[:per_tola], r[:per_ounce])
29
+ end
30
+ when "item"
31
+ r = G.item_price(price24: opt.fetch("price"), weight: opt.fetch("weight"), unit: opt.fetch("unit", "g"),
32
+ karat: G.parse_number(opt.fetch("karat", "24")), making: opt.fetch("making", "0"),
33
+ making_type: opt.fetch("making-type", "per_gram"), vat_rate: opt.fetch("vat", "0.05"))
34
+ puts format("%s: %.2f %s", ar ? "قيمة الذهب" : "Gold value", r[:metal], cur)
35
+ puts format("%s: %.2f %s", ar ? "المصنعية" : "Making charge", r[:making], cur)
36
+ puts format("%s: %.2f %s", ar ? "ضريبة القيمة المضافة" : "VAT", r[:vat], cur)
37
+ puts format("%s: %.2f %s", ar ? "الإجمالي" : "Total", r[:total], cur)
38
+ when "zakat"
39
+ z = G.zakat(opt.fetch("price"), [{ weight: opt.fetch("weight"), unit: opt.fetch("unit", "g"),
40
+ karat: G.parse_number(opt.fetch("karat", "24")) }])
41
+ puts(z[:due] ? format("%s: %.2f %s", ar ? "الزكاة المستحقة" : "Zakat due", z[:zakat], cur) : (ar ? "أقل من النصاب: لا زكاة" : "Below nisab: no zakat due"))
42
+ else
43
+ puts "uae-gold-calculator #{G::VERSION}: table | item | convert | zakat. Today's 24K price: https://uaegoldprices.ae/"
44
+ end
45
+ rescue KeyError, ArgumentError => e
46
+ warn "Error: #{e.message}"
47
+ exit 1
48
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Gold value maths for the UAE market: karat prices, unit conversion, making
4
+ # charges, VAT and zakat. Pure Ruby, no network. Pass today's 24K price per
5
+ # gram (for example from https://uaegoldprices.ae/).
6
+ module UaeGoldCalculator
7
+ VERSION = "1.0.0"
8
+ KARATS = [24, 22, 21, 18, 14].freeze
9
+ # Fineness per mille used by UAE gold price boards (and uaegoldprices.ae).
10
+ # A karat's price = 24K price x fineness / 999; other karats use karat / 24.
11
+ HALLMARKS = { 24 => 999, 22 => 914, 21 => 874, 18 => 749, 16 => 666, 14 => 583 }.freeze
12
+ UNITS = { "g" => 1.0, "kg" => 1000.0, "oz" => 31.1034768, "tola" => 11.6638038, "mithqal" => 4.25 }.freeze
13
+ ALIASES = {
14
+ "gram" => "g", "grams" => "g", "gr" => "g", "جرام" => "g", "غرام" => "g",
15
+ "kilogram" => "kg", "kilo" => "kg", "كيلو" => "kg",
16
+ "ounce" => "oz", "ozt" => "oz", "troy_ounce" => "oz", "troy-ounce" => "oz", "أونصة" => "oz", "اونصة" => "oz",
17
+ "tolas" => "tola", "تولة" => "tola", "mithqals" => "mithqal", "misqal" => "mithqal", "مثقال" => "mithqal"
18
+ }.freeze
19
+ UAE_VAT_RATE = 0.05
20
+ NISAB_GRAMS = 85.0
21
+ ZAKAT_RATE = 0.025
22
+
23
+ module_function
24
+
25
+ # Round half away from zero.
26
+ def round_money(x, dp = 2)
27
+ f = 10.0**dp
28
+ v = ((x.abs * f) + 1e-9).round / f
29
+ x.negative? ? -v : v
30
+ end
31
+
32
+ # Parse "461.11", "461,11", "14,342.21" or Arabic-Indic "٤٦١٫١١".
33
+ def parse_number(value)
34
+ return value.to_f if value.is_a?(Numeric)
35
+
36
+ s = value.to_s.strip.tr("٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹٫", "01234567890123456789.").delete("٬").gsub(/\s/, "")
37
+ s = s.match?(/\A\d{1,3}(,\d{3})+(\.\d+)?\z/) ? s.delete(",") : s.sub(",", ".")
38
+ Float(s)
39
+ rescue ArgumentError, TypeError
40
+ raise ArgumentError, "not a number: #{value}"
41
+ end
42
+
43
+ def normalize_unit(unit)
44
+ u = (unit || "g").to_s.strip.downcase
45
+ k = ALIASES.fetch(u, u)
46
+ raise ArgumentError, "unknown unit: #{unit}. Use g, kg, oz, tola or mithqal" unless UNITS.key?(k)
47
+
48
+ k
49
+ end
50
+
51
+ def check(name, v, allow_zero: false)
52
+ if !v.finite? || v.negative? || (!allow_zero && v.zero?)
53
+ raise ArgumentError, "#{name} must be #{allow_zero ? 'non-negative' : 'positive'}"
54
+ end
55
+
56
+ v
57
+ end
58
+
59
+ def purity(karat)
60
+ k = karat.to_f
61
+ raise ArgumentError, "karat must be between 0 and 24" unless k.positive? && k <= 24
62
+ return 1.0 if k == 24
63
+
64
+ f = k == k.floor ? HALLMARKS[k.to_i] : nil
65
+ f ? f / 999.0 : k / 24
66
+ end
67
+
68
+ def convert(value, from, to)
69
+ check("value", parse_number(value), allow_zero: true) * UNITS[normalize_unit(from)] / UNITS[normalize_unit(to)]
70
+ end
71
+
72
+ def karat_price(price24, karat)
73
+ check("price24", parse_number(price24)) * purity(karat)
74
+ end
75
+
76
+ def price_table(price24)
77
+ KARATS.map do |k|
78
+ g = karat_price(price24, k)
79
+ { karat: k, hallmark: HALLMARKS[k], per_gram: round_money(g),
80
+ per_tola: round_money(g * UNITS["tola"]), per_ounce: round_money(g * UNITS["oz"]) }
81
+ end
82
+ end
83
+
84
+ def item_price(price24:, weight:, unit: "g", karat: 24, making: 0, making_type: :per_gram, vat_rate: UAE_VAT_RATE)
85
+ grams = check("weight", parse_number(weight)) * UNITS[normalize_unit(unit)]
86
+ per_gram = karat_price(price24, karat)
87
+ metal = grams * per_gram
88
+ m = check("making", parse_number(making), allow_zero: true)
89
+ mk = case making_type.to_sym
90
+ when :per_gram then m * grams
91
+ when :percent then metal * m / 100
92
+ when :fixed then m
93
+ else raise ArgumentError, "making_type must be per_gram, percent or fixed"
94
+ end
95
+ rate = check("vat_rate", parse_number(vat_rate), allow_zero: true)
96
+ sub = metal + mk
97
+ { grams: round_money(grams, 4), price_per_gram: round_money(per_gram), metal: round_money(metal),
98
+ making: round_money(mk), subtotal: round_money(sub), vat_rate: rate, vat: round_money(sub * rate),
99
+ total: round_money(sub + (sub * rate)) }
100
+ end
101
+
102
+ # items: [{ weight: 100, karat: 21, unit: "g" }]
103
+ def zakat(price24, items)
104
+ p = check("price24", parse_number(price24))
105
+ pure = items.sum do |it|
106
+ check("weight", parse_number(it[:weight]), allow_zero: true) * UNITS[normalize_unit(it[:unit])] * purity(it.fetch(:karat, 24))
107
+ end
108
+ value = pure * p
109
+ due = pure + 1e-9 >= NISAB_GRAMS
110
+ { pure_grams: round_money(pure, 4), value: round_money(value), nisab_value: round_money(NISAB_GRAMS * p),
111
+ due: due, zakat: due ? round_money(value * ZAKAT_RATE) : 0.0 }
112
+ end
113
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: uae-gold-calculator
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - UAE Gold Prices
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: 'Price gold in AED from today''s 24K rate: 24/22/21/18/14K per gram,
13
+ tola and troy ounce, making charges (per gram, percent or fixed), 5% VAT and zakat
14
+ against the 85 g nisab. Accepts Arabic-Indic digits and Arabic unit names. Library
15
+ + CLI, no dependencies.'
16
+ executables:
17
+ - uae-gold-calculator
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE
22
+ - README.md
23
+ - exe/uae-gold-calculator
24
+ - lib/uae_gold_calculator.rb
25
+ homepage: https://uaegoldprices.ae/
26
+ licenses:
27
+ - MIT
28
+ metadata:
29
+ homepage_uri: https://uaegoldprices.ae/
30
+ source_code_uri: https://github.com/nbkdevs/uae-gold-prices
31
+ bug_tracker_uri: https://github.com/nbkdevs/uae-gold-prices/issues
32
+ rubygems_mfa_required: 'true'
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '2.7'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubygems_version: 4.0.20
48
+ specification_version: 4
49
+ summary: 'Gold value calculator for the UAE: karat prices, making charges, 5% VAT
50
+ and zakat.'
51
+ test_files: []