e_plat 0.2.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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +339 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/e_plat_manifest.js +0 -0
  6. data/config/routes.rb +2 -0
  7. data/lib/active_resource/schema.rb +59 -0
  8. data/lib/e_plat/client/default_request_args.rb +33 -0
  9. data/lib/e_plat/client/platform_convenience_methods.rb +21 -0
  10. data/lib/e_plat/client.rb +95 -0
  11. data/lib/e_plat/engine.rb +4 -0
  12. data/lib/e_plat/errors/incorrect_type_error.rb +8 -0
  13. data/lib/e_plat/errors/missing_migration_key_error.rb +9 -0
  14. data/lib/e_plat/errors/missing_session_error.rb +8 -0
  15. data/lib/e_plat/mapping/base.rb +49 -0
  16. data/lib/e_plat/mapping/bigcommerce/v_3/product/image.rb +55 -0
  17. data/lib/e_plat/mapping/bigcommerce/v_3/product/variant.rb +96 -0
  18. data/lib/e_plat/mapping/bigcommerce/v_3/product.rb +129 -0
  19. data/lib/e_plat/mapping/bigcommerce/v_3/shop.rb +103 -0
  20. data/lib/e_plat/mapping/shopify/v_2022_07/product/image.rb +32 -0
  21. data/lib/e_plat/mapping/shopify/v_2022_07/product/variant.rb +30 -0
  22. data/lib/e_plat/mapping/shopify/v_2022_07/product.rb +26 -0
  23. data/lib/e_plat/mapping/shopify/v_2022_07/shop.rb +26 -0
  24. data/lib/e_plat/mapping.rb +19 -0
  25. data/lib/e_plat/resource/attribute_interface.rb +60 -0
  26. data/lib/e_plat/resource/base.rb +145 -0
  27. data/lib/e_plat/resource/concerns/aliases.rb +100 -0
  28. data/lib/e_plat/resource/concerns/overwrite_instance_methods.rb +11 -0
  29. data/lib/e_plat/resource/concerns/overwrite_request_methods.rb +50 -0
  30. data/lib/e_plat/resource/order/customer.rb +37 -0
  31. data/lib/e_plat/resource/order/fulfillment.rb +27 -0
  32. data/lib/e_plat/resource/order/line_item.rb +37 -0
  33. data/lib/e_plat/resource/order/shipping_line.rb +24 -0
  34. data/lib/e_plat/resource/order.rb +103 -0
  35. data/lib/e_plat/resource/product/image.rb +25 -0
  36. data/lib/e_plat/resource/product/option.rb +16 -0
  37. data/lib/e_plat/resource/product/variant.rb +51 -0
  38. data/lib/e_plat/resource/product.rb +35 -0
  39. data/lib/e_plat/resource/shop.rb +79 -0
  40. data/lib/e_plat/session.rb +20 -0
  41. data/lib/e_plat/session_state.rb +25 -0
  42. data/lib/e_plat/type_coercer.rb +59 -0
  43. data/lib/e_plat/types.rb +15 -0
  44. data/lib/e_plat/version.rb +3 -0
  45. data/lib/e_plat.rb +29 -0
  46. data/lib/tasks/e_plat_tasks.rake +4 -0
  47. metadata +256 -0
@@ -0,0 +1,145 @@
1
+
2
+
3
+ module EPlat
4
+ class Base < ActiveResource::Base
5
+
6
+ class << self
7
+ include Dry::Effects.State(:e_plat_session)
8
+ include Concerns::OverwriteRequestMethods
9
+ threadsafe_attribute :client, :mapping, :include_root_in_json, :include_format_in_path
10
+
11
+ def initialize_singleton!
12
+ self.client = e_plat_session
13
+
14
+ self.site = client.base_url
15
+ self.prefix = client.url_prefix
16
+
17
+ self.timeout = 5
18
+ self.include_format_in_path = !client.bigcommerce?
19
+ self.mapping = mapping_instance
20
+
21
+ client.platform_headers.each {|name, value| self.headers[name] = value}
22
+ end
23
+
24
+ def find_by(title:)
25
+ find(:all, params: { title: title })&.first
26
+ end
27
+
28
+ private
29
+
30
+ def mapping_instance
31
+ class_constant_string = element_name.capitalize
32
+ mapping_class_name = "EPlat::Mapping::#{ client.platform.capitalize }::V#{ client.api_version.camelize }::#{ class_constant_string }"
33
+
34
+ EPlat::Mapping.new_instance(specifc_mapping: mapping_class_name)
35
+ end
36
+
37
+ end
38
+
39
+
40
+ include Dry::Effects.State(:e_plat_session)
41
+ include Concerns::Aliases, Concerns::OverwriteInstanceMethods
42
+
43
+ attr_accessor :client, :mapping, :mapped_attributes
44
+
45
+ def initialize(attributes = {}, persisted = false)
46
+ self.client = e_plat_session
47
+ site = client.base_url
48
+ self.mapping = mapping_instance
49
+ ActiveResource::Base.include_root_in_json = client.shopify? && top_level_resource?
50
+
51
+ super
52
+
53
+ add_aliases!(mapping.native_attribute_aliases, schema)
54
+ @mapped_attributes = AttributeInterface.new(self, keys: mappable_keys)
55
+ end
56
+
57
+ def mapped?(attribute)
58
+ mapped_attributes.include? attribute.to_s
59
+ end
60
+
61
+ def native_keys
62
+ (client.shopify?) ? schema.keys : @mapping.native_attributes.presence
63
+ end
64
+
65
+ private
66
+
67
+ def mapping_instance
68
+ class_constant_string = self.class.to_s.gsub("EPlat::", "")
69
+ mapping_class_name = "EPlat::Mapping::#{ client.platform.capitalize }::V#{ client.api_version.camelize }::#{ class_constant_string }"
70
+
71
+ EPlat::Mapping.new_instance(specifc_mapping: mapping_class_name)
72
+ end
73
+
74
+ def mappable_keys
75
+ mappable_keys = mapping.mappable_keys
76
+ (mappable_keys == :all) ? schema.keys : mappable_keys
77
+ end
78
+
79
+ def type_check!(schema)
80
+ schema.each{|name, type| type_attr!(name, type) }
81
+ end
82
+
83
+ def type_attr!(name, type)
84
+ current_value = attributes.send(:[], name) || self.send(name.to_sym)
85
+ return if current_value.nil? and !(type == "array" or type == "hash")
86
+
87
+ typed_value =
88
+ case type
89
+ when "datetime"
90
+ current_value.to_datetime
91
+ when "boolean"
92
+ current_value?
93
+ else
94
+ "EPlat::Types::Coercible::#{ type.capitalize }".constantize[current_value]
95
+ end
96
+
97
+ self.send("#{name}=", typed_value)
98
+ end
99
+
100
+ def top_level_resource?
101
+ [
102
+ "product",
103
+ "order"
104
+ ].include? self.class.element_name
105
+ end
106
+
107
+ end
108
+
109
+
110
+ end
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+ ###### api call methods
119
+
120
+ ### create new entry
121
+ # product = EPlat::Product.new(:title => 't-shirt')
122
+ # t-shirt.save
123
+ # or... EPlat::Product.create(:title => 't-shirt')
124
+ # new_product = product.dup #duplicates entry without saving
125
+
126
+ ### delete record
127
+ # EPlat::Product.delete(params[:id])
128
+ # EPlat::Product.find(my_id).destroy
129
+
130
+ ### save record
131
+ # product = EPlat::Product.new(:title => 't-shirt')
132
+ # product.save
133
+
134
+ ### get records
135
+ # EPlat::Product.find(1) # => GET /people/1.json (or EPlat::Product.first(args)) (or EPlat::Product.last(args))
136
+ # EPlat::Product.find(:all) # => GET /people.json
137
+ # EPlat::Product.find(:all, :params => { :title => "tshirt" }) # => GET /product.json?title=tshirt
138
+ # EPlat::Product.find(:one, :from => :leader) # => GET /product/leader.json
139
+ # EPlat::Product.find(:one, :from => "/companies/1/manager.json") # => GET /companies/1/manager.json
140
+
141
+
142
+ #### options
143
+ # prefix_options #for nested URLs Comment.collection_path(:post_id => 5) # => /posts/5/comments.json
144
+ # query_options #to add to params ?x=y
145
+ # instance.known_attributes #to return mix of schema and native attributes
@@ -0,0 +1,100 @@
1
+
2
+ module EPlat
3
+ module Concerns
4
+ module Aliases
5
+ extend ActiveSupport::Concern
6
+ attr_accessor :type_coercer
7
+
8
+ def add_aliases!(aliases, type_schema)
9
+ @type_coercer = EPlat::TypeCoercer.new(type_schema)
10
+ processed = []
11
+
12
+ aliases.each do |action|
13
+ action_name = action.keys.first
14
+ args = action.values.first
15
+ e_plat_key = args[:e_plat_key]
16
+ native_key = args[:native_key]
17
+
18
+ case action_name
19
+ when :alias_attribute
20
+ add_to_instance! alias_mapped_getter(e_plat_key, native_key, proc: args[:custom_e_plat_getter])
21
+ add_to_instance! alias_mapped_setter(e_plat_key, native_key, proc: args[:custom_native_setter])
22
+ processed << e_plat_key
23
+ end
24
+ end
25
+
26
+ type_schema.each do |e_plat_key, type|
27
+ next if processed.include?(e_plat_key)
28
+ add_to_instance! mapped_getter(e_plat_key)
29
+ end
30
+
31
+ end
32
+
33
+
34
+ private
35
+
36
+
37
+ def alias_mapped_getter(e_plat_key, native_key, proc: nil)
38
+ proc_line = (proc) ? "current_value = #{ proc.strip }.call(current_value)" : nil
39
+
40
+ <<-STRING
41
+ def #{ e_plat_key }
42
+ current_value = self.attributes['#{ native_key }']
43
+ #{ proc_line }
44
+ type_coercer.type_value!('#{ e_plat_key }', current_value)
45
+ end
46
+ STRING
47
+ end
48
+
49
+ def alias_mapped_setter(e_plat_key, native_key, proc: nil)
50
+ proc_line = (proc) ? "new_value = #{ proc.strip }.call(new_value)" : nil
51
+
52
+ <<-STRING
53
+ def #{ e_plat_key }=(value)
54
+ new_value = value
55
+ #{proc_line}
56
+ self.attributes['#{ native_key }'] = new_value
57
+ end
58
+ STRING
59
+ end
60
+
61
+ def mapped_getter(e_plat_key)
62
+ <<-STRING
63
+ def #{ e_plat_key }
64
+ type_coercer.type_value!('#{ e_plat_key }', self.attributes['#{ e_plat_key }'])
65
+ end
66
+ STRING
67
+ end
68
+
69
+ def add_to_instance!(meta_programming_string)
70
+ self.instance_eval { eval meta_programming_string }
71
+ end
72
+
73
+
74
+
75
+ # Requires an array of hashes which each contain a single :alias_attribute entry.
76
+ # This will expose e_plat_key getter and setter methods that interact with the
77
+ # native_key attribute.
78
+
79
+ # This pattern allows us to interact with the resource via the same universal e_plat interface, whatever the platform.
80
+ # Then when it's time to make a save back to the platform, the native attributes are already ready.
81
+ #
82
+ # Like the below example, optional stringified procs can be passed in to respect the e_plat or native interfaces version of the value. e.g. enums
83
+ #
84
+ # {
85
+ # alias_attribute: {native_key: "name", e_plat_key: "handle"}
86
+ # },
87
+ # {
88
+ # alias_attribute: {native_key: "availability", e_plat_key: "status",
89
+ # custom_e_plat_getter: "-> (value) {
90
+ # {'preorder'=>'active', 'available' => 'active', 'disabled' => 'draft'}[value] || value
91
+ # }",
92
+ # custom_native_setter: "-> (value) {
93
+ # {'available' => 'active', 'disabled' => 'draft'}.invert[value] || value
94
+ # }" #invert will merge new duped keys
95
+ # }
96
+ # }
97
+
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,11 @@
1
+ module EPlat
2
+ module Concerns
3
+ module OverwriteInstanceMethods
4
+
5
+ def include_root_in_json
6
+ client.shopify? && top_level_resource?
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ module EPlat
2
+ module Concerns
3
+ module OverwriteRequestMethods
4
+
5
+ def find(*arguments)
6
+ initialize_singleton!
7
+ arguments.second[:params].merge!(client.send "#{element_name}_default_find_args") if arguments.second
8
+ arguments.second[:params].merge!(mapping.to_native_keys arguments.second[:params]) if arguments.second
9
+
10
+ super
11
+ end
12
+
13
+ def instantiate_collection(collection, original_params = {}, prefix_options = {})
14
+ collection = collection["data"] if collection.is_a?(Hash) && collection["data"].present?
15
+
16
+ super
17
+ end
18
+
19
+ def new(attributes, persisted=false)
20
+ initialize_singleton!
21
+ self.mapping = EPlat::Mapping.new_instance(specifc_mapping: specifc_mapping_name)
22
+
23
+ attributes = attributes.send( *top_key_method(mapping.native_top_key) ) if attributes[mapping.native_top_key]
24
+ super
25
+ end
26
+
27
+ def create(attributes = {})
28
+ initialize_singleton!
29
+ super
30
+ end
31
+
32
+ def include_root_in_json
33
+ client.shopify? && top_level_resource?
34
+ end
35
+
36
+
37
+ private
38
+
39
+ def top_key_method(top_key)
40
+ (top_key == :itself) ? top_key : [:[], top_key]
41
+ end
42
+
43
+ def specifc_mapping_name
44
+ class_constant_string = self.name.gsub("EPlat::", "")
45
+ "EPlat::Mapping::#{ client.platform.capitalize }::V#{ client.api_version.camelize }::#{ class_constant_string }"
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,37 @@
1
+
2
+ module EPlat
3
+ class Order::Customer < Base
4
+
5
+ schema do
6
+ array :addresses, item_type: :hash
7
+ string :currency
8
+ date_time :created_at
9
+ hash :default_address
10
+ string :email
11
+ hash :email_marketing_consent
12
+ string :first_name
13
+ integer :id
14
+ string :last_name
15
+ integer :last_order_id
16
+ string :last_order_name
17
+ hash :metafield
18
+ string :marketing_opt_in_level
19
+ string :multipass_identifier
20
+ string :note
21
+ integer :orders_count
22
+ string :password
23
+ string :password_confirmation
24
+ string :phone
25
+ hash :sms_marketing_consent
26
+ string :state
27
+ string :tags
28
+ boolean :tax_exempt
29
+ array :tax_exemptions
30
+ decimal :total_spent
31
+ date_time :updated_at
32
+ boolean :verified_email
33
+ end
34
+
35
+ end
36
+ end
37
+
@@ -0,0 +1,27 @@
1
+
2
+ module EPlat
3
+ class Order::Fulfillment < Base
4
+
5
+ schema do
6
+ string :created_at
7
+ integer :id
8
+ array :line_items
9
+ integer :location_id
10
+ string :name
11
+ boolean :notify_customer
12
+ integer :order_id
13
+ array :origin_address
14
+ hash :receipt
15
+ string :service
16
+ string :shipment_status
17
+ string :status
18
+ string :tracking_company
19
+ array :tracking_numbers
20
+ array :tracking_urls
21
+ string :updated_at
22
+ string :variant_inventory_management
23
+ end
24
+
25
+ end
26
+ end
27
+
@@ -0,0 +1,37 @@
1
+
2
+ module EPlat
3
+ class Order::LineItem < Base
4
+
5
+ schema do
6
+ integer :id
7
+ string :admin_graphql_api_id
8
+ integer :fulfillable_quantity
9
+ string :fulfillment_service
10
+ string :fulfillment_status
11
+ boolean :gift_card
12
+ integer :grams
13
+ string :name
14
+ string :price
15
+ hash :price_set
16
+ boolean :product_exists
17
+ integer :product_id
18
+ array :properties
19
+ integer :quantity
20
+ boolean :requires_shipping
21
+ string :sku
22
+ boolean :taxable
23
+ string :title
24
+ string :total_discount
25
+ hash :total_discount_set
26
+ integer :variant_id
27
+ string :variant_inventory_management
28
+ string :variant_title
29
+ string :vendor
30
+ array :tax_lines
31
+ array :duties
32
+ array :discount_allocations
33
+ end
34
+
35
+ end
36
+ end
37
+
@@ -0,0 +1,24 @@
1
+
2
+ module EPlat
3
+ class Order::ShippingLine < Base
4
+
5
+ schema do
6
+ integer :id
7
+ string :carrier_identifier
8
+ string :code
9
+ string :delivery_category
10
+ string :discounted_price
11
+ hash :discounted_price_set
12
+ string :phone
13
+ string :price
14
+ hash :price_set
15
+ integer :requested_fulfillment_service_id
16
+ string :source
17
+ string :title
18
+ array :tax_lines
19
+ array :discount_allocations
20
+ end
21
+
22
+ end
23
+ end
24
+
@@ -0,0 +1,103 @@
1
+
2
+ module EPlat
3
+ class Order < Base
4
+
5
+ schema do
6
+ integer :app_id
7
+ string :billing_address_address1
8
+ string :billing_address_address2
9
+ string :billing_address_city
10
+ string :billing_address_company
11
+ string :billing_address_country
12
+ string :billing_address_first_name
13
+ string :billing_address_last_name
14
+ string :billing_address_phone
15
+ string :billing_address_province
16
+ string :billing_address_zip
17
+ string :billing_address_name
18
+ string :billing_address_province_code
19
+ string :billing_address_country_code
20
+ string :billing_address_latitude
21
+ string :billing_address_longitude
22
+ string :browser_ip
23
+ boolean :buyer_accepts_marketing
24
+ string :cancel_reason
25
+ datetime :cancelled_at
26
+ string :cart_token
27
+ string :checkout_token
28
+ hash :client_details
29
+ datetime :closed_at
30
+ datetime :created_at
31
+ string :currency
32
+ string :current_total_discounts
33
+ hash :current_total_discounts_set
34
+ hash :current_total_duties_set
35
+ string :current_total_price
36
+ hash :current_total_price_set
37
+ string :current_subtotal_price
38
+ hash :current_subtotal_price_set
39
+ string :current_total_tax
40
+ hash :current_total_tax_set
41
+ string :customer_locale
42
+ integer :device_id
43
+ array :discount_codes
44
+ string :email
45
+ boolean :estimated_taxes
46
+ string :financial_status
47
+ string :fulfillment_status
48
+ string :gateway
49
+ string :landing_site
50
+ string :landing_site_ref
51
+ integer :location_id
52
+ integer :merchant_of_record_app_id
53
+ string :name
54
+ string :note
55
+ array :note_attributes
56
+ integer :number
57
+ integer :order_number
58
+ string :order_status_url
59
+ hash :original_total_duties_set
60
+ array :payment_gateway_names
61
+ string :phone
62
+ string :presentment_currency
63
+ string :processed_at
64
+ string :processing_method
65
+ string :reference
66
+ string :referring_site
67
+ string :source_identifier
68
+ string :source_name
69
+ string :source_url
70
+ string :subtotal_price
71
+ hash :subtotal_price_set
72
+ string :tags
73
+ array :tax_lines
74
+ boolean :taxes_included
75
+ boolean :test
76
+ string :token
77
+ string :total_discounts
78
+ hash :total_discounts_set
79
+ string :total_line_items_price
80
+ hash :total_line_items_price_set
81
+ string :total_outstanding
82
+ string :total_price
83
+ hash :total_price_set
84
+ hash :total_shipping_price_set
85
+ string :total_tax
86
+ hash :total_tax_set
87
+ string :total_tip_received
88
+ integer :total_weight
89
+ datetime :updated_at
90
+ hash :billing_address
91
+ hash :customer
92
+ array :discount_applications
93
+ array :fulfillments
94
+ array :line_items
95
+ hash :payment_details
96
+ hash :payment_terms
97
+ array :refunds
98
+ hash :shipping_address
99
+ array :shipping_lines
100
+ end
101
+
102
+ end
103
+
@@ -0,0 +1,25 @@
1
+
2
+ module EPlat
3
+ class Product
4
+ class Image < Base
5
+
6
+ class << self
7
+ end
8
+
9
+ schema do
10
+ integer :id
11
+ integer :product_id
12
+ integer :position
13
+ datetime :created_at
14
+ datetime :updated_at
15
+ string :alt
16
+ integer :width
17
+ integer :height
18
+ string :src
19
+ array :variant_ids
20
+ string :admin_graphql_api_id
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+
2
+ module EPlat
3
+ class Product
4
+ class Option < Base
5
+
6
+ schema do
7
+ integer :id
8
+ integer :product_id
9
+ string :name
10
+ integer :position
11
+ array :values
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,51 @@
1
+
2
+ module EPlat
3
+ class Product
4
+ class Variant < Base
5
+
6
+ class << self
7
+ end
8
+
9
+ schema do
10
+ integer :id
11
+ integer :product_id
12
+ string :title
13
+ string :price
14
+ string :sku
15
+ integer :position
16
+ string :inventory_policy
17
+ string :compare_at_price
18
+ string :fulfillment_service
19
+ string :inventory_management
20
+ string :option1
21
+ string :option2
22
+ string :option3
23
+ datetime :created_at
24
+ datetime :updated_at
25
+ boolean :taxable
26
+ string :barcode
27
+ integer :grams
28
+ integer :image_id
29
+ float :weight
30
+ string :weight_unit
31
+ integer :inventory_item_id
32
+ integer :inventory_quantity
33
+ integer :old_inventory_quantity
34
+ array :presentment_prices
35
+ string :tax_code
36
+ boolean :requires_shipping
37
+ string :admin_graphql_api_id
38
+
39
+ hash :e_plat_option_hash
40
+ end
41
+
42
+
43
+ def testing
44
+ puts "Im just testing"
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+
51
+
@@ -0,0 +1,35 @@
1
+ module EPlat
2
+ class Product < Base
3
+ has_many :variant, class_name: "EPlat::Product::Variant"
4
+ has_many :image, class_name: "EPlat::Product::Image"
5
+
6
+ schema do
7
+ string :body_html
8
+ datetime :created_at
9
+ string :handle
10
+ integer :id
11
+ array :images
12
+ array :options
13
+ string :product_type
14
+ datetime :published_at
15
+ string :published_scope
16
+ string :status
17
+ string :tags
18
+ string :admin_graphql_api_id
19
+ string :template_suffix
20
+ string :title
21
+ datetime :updated_at
22
+ array :variants
23
+ string :vendor
24
+ end
25
+
26
+ def handle
27
+ super&.parameterize
28
+ end
29
+
30
+ def status
31
+ super || "active"
32
+ end
33
+
34
+ end
35
+ end