smerp-quotation 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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