smerp-quotation 0.1.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.
@@ -0,0 +1,76 @@
1
+
2
+ require 'securerandom'
3
+ require 'yaml'
4
+
5
+ module Smerp
6
+ module Quotation
7
+ module ExtendedCalculator
8
+ attr_accessor :input_field, :output_field
9
+ attr_accessor :params
10
+ attr_accessor :listener
11
+ attr_accessor :owner, :owner_id
12
+ attr_accessor :ecid
13
+
14
+ attr_reader :result
15
+
16
+ class ExtendedCalculatorException < StandardError; end
17
+
18
+ def initialize(params)
19
+ @params = params
20
+ @output_field = nil
21
+ @ecid = SecureRandom.uuid
22
+ end
23
+
24
+ def for_storage
25
+ inst = self.clone
26
+ inst.remove_instance_variable(:@intLogger) if inst.instance_variable_defined?(:@intLogger)
27
+ inst.remove_instance_variable(:@teLogger) if inst.instance_variable_defined?(:@teLogger)
28
+ if not inst.result.nil?
29
+ inst.result.remove_instance_variable(:@intLogger) if inst.result.instance_variable_defined?(:@intLogger)
30
+ inst.result.remove_instance_variable(:@teLogger) if inst.result.instance_variable_defined?(:@teLogger)
31
+ end
32
+
33
+ inst.remove_instance_variable(:@listener) if not_empty?(inst.listener)
34
+ inst
35
+ end
36
+
37
+ def self.instance(type, params = nil)
38
+ case type
39
+ when :discount
40
+ DiscountCalculator.new(params)
41
+ when :round_up, :roundup
42
+ RoundUpCalculator.new(params)
43
+ when :tax
44
+ TaxCalculator.new(params)
45
+ else
46
+ raise ExtendedCalculatorException, "Unknown extended calculator type '#{type}'"
47
+ end
48
+ end
49
+
50
+ def self.instance_from_hash(val = { })
51
+ inst = instance(val[:calType], val[:params])
52
+ inst.input_field = val[:input_field]
53
+ inst.output_field = val[:output_field]
54
+ inst
55
+ end
56
+
57
+ def self.from_storage(str)
58
+ YAML.load(str)
59
+ end
60
+
61
+ protected
62
+ def trigger_listener(evt, mdl)
63
+ if not @listener.nil? and @listener.is_a?(Proc)
64
+ @listener.call(evt, mdl, self)
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+
72
+ Dir.glob(File.join(File.dirname(__FILE__),"calculators/*.rb")).each do |f|
73
+ require_relative File.expand_path(f)
74
+ end
75
+
76
+
@@ -0,0 +1,72 @@
1
+
2
+ require_relative 'quotation_item_manager'
3
+
4
+ module Smerp
5
+ module Quotation
6
+ class ItemGroupManager
7
+ include TR::CondUtils
8
+
9
+ def initialize(name, quotId)
10
+ _group.name = name
11
+ _group.quotation_id = quotId
12
+ _group.save
13
+ end
14
+
15
+ def add(name, qty = 1, unit = "Unit", unit_price = '0.0', notes = nil, ops = { }, &block)
16
+ qi = QuotationItemManager.new
17
+
18
+ qi.quotation_id = _group.quotation_id
19
+
20
+ qi.name = name
21
+ qi.quantity = qty
22
+ qi.unit = unit
23
+ qi.unit_price = unit_price
24
+ qi.notes = notes
25
+
26
+ qi.quotation_item_group_id = _group.id
27
+
28
+ if not_empty?(ops) and not_empty?(ops[:transform])
29
+ qi.apply_discount(ops[:transform][:discount]) if not_empty?(ops[:transform][:discount])
30
+ qi.apply_tax(ops[:transform][:tax]) if not_empty?(ops[:transform][:tax])
31
+ end
32
+
33
+ qi.save
34
+
35
+ if block
36
+ yield(qi)
37
+ end
38
+
39
+ qi.reload
40
+ qi
41
+
42
+ end
43
+
44
+ def group(name, &block)
45
+ g = ItemGroupManager.new(name, _group.quotation_id)
46
+ g.parent_id = _group.id
47
+ g.save
48
+
49
+ if block
50
+ yield(g)
51
+ end
52
+
53
+ g.reload
54
+ g
55
+
56
+ end
57
+
58
+ private
59
+ def _group
60
+ if @_group.nil?
61
+ @_group = ArModel::QuotationItemGroup.new
62
+ end
63
+ @_group
64
+ end
65
+
66
+ def method_missing(mtd, *args, &block)
67
+ _group.send(mtd, *args, &block)
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,112 @@
1
+
2
+
3
+
4
+ module Smerp
5
+ module Quotation
6
+ class QuotationItemManager
7
+ include TR::CondUtils
8
+ include TeLogger::TeLogHelper
9
+ teLogger_tag :quotItemMgr
10
+
11
+ class QuotationItemManagerException < StandardError; end
12
+
13
+ # add as children
14
+ def add(name, qty = 1, unit = "Unit", unit_price = 0.0, notes = nil, ops = { }, &block)
15
+
16
+ cqi = QuotationItemManager.new
17
+ cqi.quotation_id = quotation_item.quotation_id
18
+ cqi.name = name
19
+ cqi.quantity = qty
20
+ cqi.unit = unit
21
+ cqi.unit_price = unit_price
22
+ cqi.notes = notes
23
+
24
+ quotation_item.save
25
+
26
+ cqi.parent_id = quotation_item.id
27
+
28
+ if not_empty?(ops) and not_empty?(ops[:extCal])
29
+
30
+ ops[:extCal].each do |cal|
31
+
32
+ case cal
33
+ when Hash
34
+ ec = ExtendedCalculator.instance_from_hash(cal)
35
+ when ExtendedCalculator
36
+ ec = cal
37
+ else
38
+ raise ExtendedCalculatorException, "Unsupported calculator type '#{cal.class}'"
39
+ end
40
+
41
+ cqi.add_ext_cal(ec)
42
+ end
43
+
44
+ end
45
+
46
+ cqi.save
47
+
48
+ if block
49
+ yield(cqi)
50
+ end
51
+
52
+ cqi.reload
53
+ cqi
54
+
55
+ end
56
+
57
+ def group(name, &block)
58
+ g = ItemGroupManager.new(name, quotation_item.quotation_id)
59
+ g.save
60
+
61
+ if block
62
+ yield(g)
63
+ end
64
+
65
+ g.reload
66
+ g
67
+
68
+ end
69
+
70
+ #def apply_calculator(type, val, inField, outField)
71
+ # case type
72
+ # when :discount
73
+ # cal = Smerp::Quotation::DiscountCalculator.new(val)
74
+ # when :tax
75
+ # cal = Smerp::Quotation::TaxCalculator.new(val)
76
+ # when :roundup
77
+ # cal = Smerp::Quotation::RoundUpCalculator.new(val)
78
+ # end
79
+
80
+ # cal.input_field = inField
81
+ # cal.output_field = outField
82
+
83
+ # extCal = ArModel::ExtendedCalculation.new
84
+ # extCal.listening_field = cal.input_field
85
+ # extCal.calculator_spec = YAML.dump(cal)
86
+ # quotation_item.extended_calculations << extCal
87
+
88
+ #end
89
+ #def apply_discount(val, inField, outField = nil)
90
+ # apply_calculator(:discount, val, inField, outField)
91
+ #end
92
+ #def apply_tax(val, inField, outField = nil)
93
+ # apply_calculator(:tax, val, inField, outField)
94
+ #end
95
+ #def round_up(val, inField, outField = nil)
96
+ # apply_calculator(:roundup, val, inField, outField)
97
+ #end
98
+
99
+
100
+ def method_missing(mtd, *args, &block)
101
+ quotation_item.send(mtd, *args, &block)
102
+ end
103
+
104
+ def quotation_item
105
+ if @qi.nil?
106
+ @qi = ArModel::QuotationItem.new
107
+ end
108
+ @qi
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,86 @@
1
+
2
+ require_relative 'quotation_item_manager'
3
+ require_relative 'item_group_manager'
4
+
5
+ module Smerp
6
+ module Quotation
7
+ class QuotationManager
8
+ include TR::CondUtils
9
+ include TeLogger::TeLogHelper
10
+
11
+ teLogger_tag :quotMgr
12
+
13
+ def initialize(name = nil)
14
+ quotation.name = name if not_empty?(name)
15
+ quotation.save
16
+ end
17
+
18
+ #
19
+ # Add children
20
+ #
21
+ def add(name, qty = 1, unit = "Unit", unit_price = 0.0, notes = nil, ops = { }, &block)
22
+ qi = QuotationItemManager.new
23
+ qi.name = name
24
+ qi.quantity = qty
25
+ qi.unit = unit
26
+ qi.unit_price = unit_price
27
+ qi.notes = notes
28
+
29
+ qi.quotation_id = quotation.id
30
+
31
+ if not_empty?(ops) and not_empty?(ops[:extCal])
32
+
33
+ ops[:extCal].each do |cal|
34
+
35
+ case cal
36
+ when Hash
37
+ ec = ExtendedCalculator.instance_from_hash(cal)
38
+ when ExtendedCalculator
39
+ ec = cal
40
+ else
41
+ raise ExtendedCalculatorException, "Unsupported calculator type '#{cal.class}'"
42
+ end
43
+
44
+ qi.add_ext_cal(ec)
45
+ end
46
+
47
+ end
48
+
49
+ qi.save
50
+
51
+ if block
52
+ yield(qi)
53
+ end
54
+
55
+ qi.reload
56
+ qi
57
+
58
+ end
59
+
60
+ def group(name, &block)
61
+ g = ItemGroupManager.new(name, quotation.id)
62
+ g.save
63
+
64
+ if block
65
+ yield(g)
66
+ end
67
+
68
+ g.reload
69
+ g
70
+
71
+ end
72
+
73
+ def quotation
74
+ if @quotation.nil?
75
+ @quotation = ArModel::Quotation.new
76
+ end
77
+ @quotation
78
+ end
79
+
80
+ def method_missing(mtd, *args, &block)
81
+ quotation.send(mtd, *args, &block)
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,22 @@
1
+
2
+
3
+ module Smerp
4
+ module Quotation
5
+ class TaxCategoryManager
6
+ include TR::CondUtils
7
+ include TeLogger::TeLogHelper
8
+ teLogger_tag :tax_cat
9
+
10
+ def method_missing(mtd, *args, &block)
11
+ taxCat.send(mtd, *args, &block)
12
+ end
13
+
14
+ def taxCat
15
+ if @_taxCat.nil?
16
+ @_taxCat = TaxCategory.new
17
+ end
18
+ @_taxCat
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smerp
4
+ module Quotation
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'teLogger'
4
+ require 'toolrack'
5
+
6
+ require 'ca/data_store'
7
+ require 'ca/data_store/ar'
8
+
9
+ require 'state_machines-activerecord'
10
+
11
+ Ca::DataStore::Ar.connect_database
12
+ Ca::DataStore::Ar.load_model(File.join(File.dirname(__FILE__),"quotation","ar_model"))
13
+ Ca::DataStore::Ar.show_log(STDOUT)
14
+
15
+ require 'smerp/common'
16
+
17
+ require_relative "quotation/version"
18
+
19
+ require_relative 'quotation/quotation_manager'
20
+ require_relative 'quotation/extended_calculator'
21
+
22
+ module Smerp
23
+ module Quotation
24
+ class Error < StandardError; end
25
+ # Your code goes here...
26
+
27
+
28
+ def Quotation.instance(name = nil)
29
+ QuotationManager.new(name)
30
+ end
31
+
32
+ def Quotation.migration_path
33
+ File.join(File.dirname(__FILE__),"..","..","db","migrate")
34
+ end
35
+
36
+ end
37
+ end
38
+
39
+
40
+
data/schema.rb ADDED
@@ -0,0 +1,85 @@
1
+ # This file is auto-generated from the current state of the database. Instead
2
+ # of editing this file, please use the migrations feature of Active Record to
3
+ # incrementally modify your database, and then regenerate this schema definition.
4
+ #
5
+ # This file is the source Rails uses to define your schema when running `bin/rails
6
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7
+ # be faster and is potentially less error prone than running all of your
8
+ # migrations from scratch. Old migrations may fail to apply correctly if those
9
+ # migrations use external dependencies or application code.
10
+ #
11
+ # It's strongly recommended that you check this file into your version control system.
12
+
13
+ ActiveRecord::Schema[7.0].define(version: 20220922121503548314) do
14
+ create_table "quotation_item_groups", force: :cascade do |t|
15
+ t.string "name"
16
+ t.string "quotation_id"
17
+ t.string "parent_id"
18
+ t.integer "position"
19
+ t.decimal "group_total", precision: 25, scale: 2, default: "0.0"
20
+ t.decimal "group_discount", precision: 25, scale: 2, default: "0.0"
21
+ t.decimal "group_tax", precision: 25, scale: 2, default: "0.0"
22
+ t.text "smerp_domain_info"
23
+ t.datetime "created_at", null: false
24
+ t.datetime "updated_at", null: false
25
+ end
26
+
27
+ create_table "quotation_items", force: :cascade do |t|
28
+ t.string "quotation_id"
29
+ t.string "parent_id"
30
+ t.integer "position"
31
+ t.string "quotation_item_group_id"
32
+ t.string "quotable_id"
33
+ t.string "quotable_type"
34
+ t.string "name"
35
+ t.text "notes"
36
+ t.integer "children_link", limit: 1, default: 1
37
+ t.decimal "quantity", default: "0.0"
38
+ t.string "unit", default: "unit(s)"
39
+ t.decimal "unit_price", precision: 25, scale: 2, default: "0.0"
40
+ t.string "price_currency"
41
+ t.decimal "line_total", precision: 25, scale: 2, default: "0.0"
42
+ t.decimal "discount", precision: 25, scale: 2, default: "0.0"
43
+ t.decimal "line_total_after_discount", precision: 25, scale: 2, default: "0.0"
44
+ t.decimal "tax", default: "0.0"
45
+ t.decimal "line_total_with_tax", precision: 25, scale: 2, default: "0.0"
46
+ t.text "extended_calculators"
47
+ t.text "smerp_domain_info"
48
+ t.datetime "created_at", null: false
49
+ t.datetime "updated_at", null: false
50
+ end
51
+
52
+ create_table "quotations", force: :cascade do |t|
53
+ t.string "qid"
54
+ t.string "name"
55
+ t.text "address"
56
+ t.string "attention_to"
57
+ t.text "notes"
58
+ t.string "state", default: "open"
59
+ t.text "sqconfig"
60
+ t.date "qdate"
61
+ t.datetime "released_timestamp"
62
+ t.decimal "total", default: "0.0"
63
+ t.decimal "total_discount", default: "0.0"
64
+ t.decimal "total_after_discount", default: "0.0"
65
+ t.decimal "total_tax", default: "0.0"
66
+ t.decimal "total_with_tax", default: "0.0"
67
+ t.text "extended_calculators"
68
+ t.text "private_extended_calculators"
69
+ t.text "smerp_domain_info"
70
+ t.datetime "created_at", null: false
71
+ t.datetime "updated_at", null: false
72
+ end
73
+
74
+ create_table "tax_category", force: :cascade do |t|
75
+ t.string "name"
76
+ t.string "display_code"
77
+ t.decimal "tax", default: "0.0"
78
+ t.text "formula"
79
+ t.string "state", default: "active"
80
+ t.text "smerp_domain_info"
81
+ t.datetime "created_at", null: false
82
+ t.datetime "updated_at", null: false
83
+ end
84
+
85
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/smerp/quotation/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "smerp-quotation"
7
+ spec.version = Smerp::Quotation::VERSION
8
+ spec.authors = ["Ian"]
9
+ spec.email = ["cameronian0@protonmail.com"]
10
+
11
+ spec.summary = ""
12
+ spec.description = ""
13
+ spec.homepage = ""
14
+ spec.required_ruby_version = ">= 2.4.0"
15
+
16
+ #spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
17
+
18
+ #spec.metadata["homepage_uri"] = spec.homepage
19
+ #spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
20
+ #spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ `git ls-files -z`.split("\x0").reject do |f|
26
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
27
+ end
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_dependency 'toolrack'
34
+ spec.add_dependency 'teLogger'
35
+
36
+ spec.add_dependency 'state_machines-activerecord'
37
+ spec.add_dependency 'acts_as_tree'
38
+ spec.add_dependency 'acts_as_list'
39
+
40
+ spec.add_dependency 'ca-data_store'
41
+ spec.add_dependency 'ca-data_store-ar'
42
+
43
+ spec.add_development_dependency 'sqlite3'
44
+ spec.add_development_dependency 'devops_assist'
45
+
46
+ # Uncomment to register a new dependency of your gem
47
+ # spec.add_dependency "example-gem", "~> 1.0"
48
+
49
+ # For more information and examples about making a new gem, checkout our
50
+ # guide at: https://bundler.io/guides/creating_gem.html
51
+ end