e_plat 1.0.0.pre.rc.9 → 1.1.0.pre.rc.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +467 -413
  3. data/lib/e_plat/client.rb +9 -5
  4. data/lib/e_plat/mapping/base.rb +22 -3
  5. data/lib/e_plat/mapping/bigcommerce/v_3/order.rb +156 -156
  6. data/lib/e_plat/mapping/woocommerce/v_3/metafield.rb +39 -0
  7. data/lib/e_plat/mapping/woocommerce/v_3/order/billing_address.rb +79 -0
  8. data/lib/e_plat/mapping/woocommerce/v_3/order/line_item.rb +85 -0
  9. data/lib/e_plat/mapping/woocommerce/v_3/order/shipping_address.rb +71 -0
  10. data/lib/e_plat/mapping/woocommerce/v_3/order/shipping_line.rb +54 -0
  11. data/lib/e_plat/mapping/woocommerce/v_3/order.rb +189 -0
  12. data/lib/e_plat/mapping/woocommerce/v_3/product/image.rb +43 -0
  13. data/lib/e_plat/mapping/woocommerce/v_3/product/option.rb +45 -0
  14. data/lib/e_plat/mapping/woocommerce/v_3/product/variant/option_value.rb +40 -0
  15. data/lib/e_plat/mapping/woocommerce/v_3/product/variant.rb +188 -0
  16. data/lib/e_plat/mapping/woocommerce/v_3/product.rb +168 -0
  17. data/lib/e_plat/mapping/woocommerce/v_3/script_tag.rb +22 -0
  18. data/lib/e_plat/mapping/woocommerce/v_3/shop.rb +142 -0
  19. data/lib/e_plat/mapping/woocommerce/v_3/webhook.rb +52 -0
  20. data/lib/e_plat/paginated/woocommerce_pagination.rb +45 -0
  21. data/lib/e_plat/resource/attribute_interface.rb +7 -4
  22. data/lib/e_plat/resource/base.rb +12 -3
  23. data/lib/e_plat/resource/collection.rb +19 -2
  24. data/lib/e_plat/resource/concerns/aliases.rb +14 -6
  25. data/lib/e_plat/resource/concerns/metafieldable.rb +31 -10
  26. data/lib/e_plat/resource/concerns/overwrite_instance_methods.rb +1 -1
  27. data/lib/e_plat/resource/concerns/overwrite_request_methods.rb +12 -1
  28. data/lib/e_plat/resource/countable.rb +7 -0
  29. data/lib/e_plat/resource/order.rb +5 -0
  30. data/lib/e_plat/resource/paginated/link_headers.rb +1 -1
  31. data/lib/e_plat/resource/platform_specific/woocommerce/metafield.rb +41 -0
  32. data/lib/e_plat/resource/platform_specific/woocommerce/order/billing_address.rb +8 -0
  33. data/lib/e_plat/resource/platform_specific/woocommerce/order/line_item.rb +2 -0
  34. data/lib/e_plat/resource/platform_specific/woocommerce/order/shipping_address.rb +8 -0
  35. data/lib/e_plat/resource/platform_specific/woocommerce/order/shipping_line.rb +2 -0
  36. data/lib/e_plat/resource/platform_specific/woocommerce/order.rb +8 -0
  37. data/lib/e_plat/resource/platform_specific/woocommerce/product/image.rb +8 -0
  38. data/lib/e_plat/resource/platform_specific/woocommerce/product/option.rb +8 -0
  39. data/lib/e_plat/resource/platform_specific/woocommerce/product/variant/option_value.rb +10 -0
  40. data/lib/e_plat/resource/platform_specific/woocommerce/product/variant.rb +53 -0
  41. data/lib/e_plat/resource/platform_specific/woocommerce/product.rb +75 -0
  42. data/lib/e_plat/resource/platform_specific/woocommerce/script_tag.rb +5 -0
  43. data/lib/e_plat/resource/platform_specific/woocommerce/shop.rb +36 -0
  44. data/lib/e_plat/resource/platform_specific/woocommerce/webhook.rb +8 -0
  45. data/lib/e_plat/resource/product/variant.rb +2 -0
  46. data/lib/e_plat/utils/money.rb +32 -0
  47. data/lib/e_plat/version.rb +1 -1
  48. data/lib/e_plat.rb +9 -3
  49. metadata +32 -2
@@ -0,0 +1,168 @@
1
+ module EPlat
2
+ class Mapping
3
+ module Woocommerce
4
+ module V3
5
+ class Product < EPlat::Mapping::Base
6
+
7
+ def native_top_key
8
+ :itself
9
+ end
10
+
11
+ def native_attributes
12
+ super.concat([
13
+ "id",
14
+ "name",
15
+ "slug",
16
+ "permalink",
17
+ "date_created",
18
+ "date_created_gmt",
19
+ "date_modified",
20
+ "date_modified_gmt",
21
+ "type",
22
+ "status",
23
+ "featured",
24
+ "catalog_visibility",
25
+ "description",
26
+ "short_description",
27
+ "sku",
28
+ "price",
29
+ "regular_price",
30
+ "sale_price",
31
+ "date_on_sale_from",
32
+ "date_on_sale_from_gmt",
33
+ "date_on_sale_to",
34
+ "date_on_sale_to_gmt",
35
+ "on_sale",
36
+ "purchasable",
37
+ "total_sales",
38
+ "virtual",
39
+ "downloadable",
40
+ "downloads",
41
+ "download_limit",
42
+ "download_expiry",
43
+ "external_url",
44
+ "button_text",
45
+ "tax_status",
46
+ "tax_class",
47
+ "manage_stock",
48
+ "stock_quantity",
49
+ "backorders",
50
+ "backorders_allowed",
51
+ "backordered",
52
+ "low_stock_amount",
53
+ "sold_individually",
54
+ "weight",
55
+ "dimensions",
56
+ "shipping_required",
57
+ "shipping_taxable",
58
+ "shipping_class",
59
+ "shipping_class_id",
60
+ "reviews_allowed",
61
+ "average_rating",
62
+ "rating_count",
63
+ "upsell_ids",
64
+ "cross_sell_ids",
65
+ "parent_id",
66
+ "purchase_note",
67
+ "categories",
68
+ "tags",
69
+ "images",
70
+ "attributes",
71
+ "#{EPlat::PROTECTED_PREFIX}attributes", # we don't allow access to attributes directly, so we use this as a proxy
72
+ "default_attributes",
73
+ "variations",
74
+ "grouped_products",
75
+ "menu_order",
76
+ "price_html",
77
+ "related_ids",
78
+ "meta_data",
79
+ "stock_status",
80
+ "has_options",
81
+ "post_password",
82
+ "global_unique_id",
83
+ "brands"
84
+ ])
85
+ end
86
+
87
+ def native_attribute_aliases
88
+ super.concat([
89
+ {
90
+ alias_attribute: {native_key: "description", e_plat_key: "body_html"}
91
+ },
92
+ {
93
+ alias_attribute: {native_key: "date_created", e_plat_key: "created_at"}
94
+ },
95
+ {
96
+ alias_attribute: {native_key: "date_created", e_plat_key: "published_at"}
97
+ },
98
+ {
99
+ alias_attribute: {native_key: "slug", e_plat_key: "handle"}
100
+ },
101
+ {
102
+ existing_entry: {native_key: "id", e_plat_key: "id"}
103
+ },
104
+ {
105
+ existing_entry: {native_key: "images", e_plat_key: "images"}
106
+ },
107
+ {
108
+ existing_entry: {native_key: "options", e_plat_key: "options"}
109
+ },
110
+ {
111
+ existing_entry: {native_key: "status", e_plat_key: "status",
112
+ custom_e_plat_getter: "-> (value) {
113
+ status_map = {
114
+ 'publish' => 'active',
115
+ 'draft' => 'draft',
116
+ 'pending' => 'active',
117
+ 'private' => 'draft'
118
+ }
119
+ status_map[value] || 'active'
120
+ }",
121
+ custom_native_setter: "-> (value) {
122
+ status_map = {
123
+ 'active' => 'publish',
124
+ 'draft' => 'draft',
125
+ 'archived' => 'private'
126
+ }
127
+ status_map[value] || 'publish'
128
+ }"
129
+ }
130
+ },
131
+ {
132
+ alias_attribute: {native_key: "name", e_plat_key: "title"}
133
+ },
134
+ {
135
+ alias_attribute: {native_key: "date_modified", e_plat_key: "updated_at"}
136
+ },
137
+ {
138
+ alias_attribute: {native_key: "lazy_load_variants", e_plat_key: "variants"}
139
+ },
140
+ {
141
+ existing_entry: {native_key: "tags", e_plat_key: "tags",
142
+ custom_e_plat_getter: "-> (value) {
143
+ (value || []).map do |tag|
144
+ tag.is_a?(Hash) ? tag['name'] : tag.name
145
+ end.compact.join(', ')
146
+ }",
147
+ custom_native_setter: "-> (value) {
148
+ if value.is_a?(String)
149
+ value.split(',').map { |tag| tag.strip }.map { |tag| { 'name' => tag } }
150
+ else
151
+ value
152
+ end
153
+ }"
154
+ }
155
+ }
156
+ ])
157
+ end
158
+
159
+ def protected_attributes_rename_on_initialize
160
+ {
161
+ "attributes" => "options"
162
+ }
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,22 @@
1
+ module EPlat
2
+ class Mapping
3
+ module Woocommerce
4
+ module V3
5
+ class ScriptTag < EPlat::Mapping::Base
6
+ # WooCommerce ScriptTag mapping to be added later
7
+ def native_top_key
8
+ :itself
9
+ end
10
+
11
+ def native_attributes
12
+ super.concat([])
13
+ end
14
+
15
+ def native_attribute_aliases
16
+ super.concat([])
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,142 @@
1
+ module EPlat
2
+ class Mapping
3
+ module Woocommerce
4
+ module V3
5
+ class Shop < EPlat::Mapping::Base
6
+
7
+ # WooCommerce uses the `/settings/general` endpoint to get the shop details
8
+ # we lazy load the weight unit from `/settings/products/woocommerce_weight_unit` when needed
9
+
10
+ def native_top_key
11
+ :itself # The response is an array, not a nested object with a specific top key
12
+ end
13
+
14
+ def native_attributes
15
+ super.concat([
16
+ "domain", #fake, as we use client.store_url. This whole class is read_only really
17
+ "woocommerce_store_address",
18
+ "woocommerce_store_address_2",
19
+ "woocommerce_store_city",
20
+ "woocommerce_store_postcode",
21
+ "woocommerce_default_country",
22
+ "woocommerce_currency",
23
+ "woocommerce_weight_unit" # lazy loaded from settings/products instead of settings/general
24
+ ])
25
+ end
26
+
27
+ def native_attribute_aliases
28
+ super.concat([
29
+ {
30
+ alias_attribute: {
31
+ native_key: "woocommerce_store_address",
32
+ e_plat_key: "address1",
33
+ custom_e_plat_getter: "-> (value) {
34
+ value&.value
35
+ }"
36
+ }
37
+ },
38
+ {
39
+ alias_attribute: {
40
+ native_key: "woocommerce_store_address_2",
41
+ e_plat_key: "address2",
42
+ custom_e_plat_getter: "-> (value) {
43
+ value&.value
44
+ }"
45
+ }
46
+ },
47
+ {
48
+ alias_attribute: {
49
+ native_key: "woocommerce_store_city",
50
+ e_plat_key: "city",
51
+ custom_e_plat_getter: "-> (value) {
52
+ value&.value
53
+ }"
54
+ }
55
+ },
56
+ {
57
+ alias_attribute: {
58
+ native_key: "woocommerce_store_postcode",
59
+ e_plat_key: "zip",
60
+ custom_e_plat_getter: "-> (value) {
61
+ value&.value
62
+ }"
63
+ }
64
+ },
65
+ {
66
+ alias_attribute: {
67
+ native_key: "woocommerce_default_country",
68
+ e_plat_key: "country",
69
+ custom_e_plat_getter: "-> (value) {
70
+ if value.is_a?(Hash) && value['value']
71
+ # Extract just the country code part, safely handling any format
72
+ country_code = value['value'].to_s.split(':').first.to_s.gsub(/[^A-Za-z0-9]/, '')
73
+ country_code
74
+ else
75
+ value.to_s.split(':').first.to_s.gsub(/[^A-Za-z0-9]/, '')
76
+ end
77
+ }"
78
+ }
79
+ },
80
+ {
81
+ alias_attribute: {
82
+ native_key: "woocommerce_default_country",
83
+ e_plat_key: "country_code",
84
+ custom_e_plat_getter: "-> (value) {
85
+ # e.g. US:CA => US
86
+ value.default.split(':').first
87
+ }"
88
+ }
89
+ },
90
+ {
91
+ alias_attribute: {
92
+ native_key: "woocommerce_default_country",
93
+ e_plat_key: "province",
94
+ custom_e_plat_getter: "-> (value) {
95
+ # e.g. US:CA => CA
96
+ value.default.split(':').last
97
+ }"
98
+ }
99
+ },
100
+ {
101
+ alias_attribute: {
102
+ native_key: "woocommerce_currency",
103
+ e_plat_key: "currency",
104
+ custom_e_plat_getter: "-> (value) {
105
+ value&.default
106
+ }"
107
+ }
108
+ },
109
+ {
110
+ alias_attribute: {
111
+ native_key: "woocommerce_weight_unit",
112
+ e_plat_key: "weight_unit",
113
+ custom_e_plat_getter: "-> (value) {
114
+ lazy_load_weight_unit
115
+ }"
116
+ }
117
+ },
118
+ # Client store_url as domain
119
+ {
120
+ existing_entry: {
121
+ native_key: "domain",
122
+ e_plat_key: "domain",
123
+ custom_e_plat_getter: "-> (value) {
124
+ client&.store_url
125
+ }"
126
+ }
127
+ },
128
+ # Set has_storefront to true for WooCommerce
129
+ {
130
+ existing_entry: {
131
+ native_key: "has_storefront",
132
+ e_plat_key: "has_storefront",
133
+ custom_e_plat_getter: "-> (value) { true }"
134
+ }
135
+ }
136
+ ])
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,52 @@
1
+ module EPlat
2
+ class Mapping
3
+ module Woocommerce
4
+ module V3
5
+ class Webhook < EPlat::Mapping::Base
6
+
7
+ def native_top_key
8
+ :itself
9
+ end
10
+
11
+ def native_attributes
12
+ super.concat([
13
+ "id",
14
+ "name",
15
+ "status",
16
+ "topic",
17
+ "resource",
18
+ "event",
19
+ "hooks",
20
+ "delivery_url",
21
+ "secret",
22
+ "date_created",
23
+ "date_created_gmt",
24
+ "date_modified",
25
+ "date_modified_gmt"
26
+ ])
27
+ end
28
+
29
+ def native_attribute_aliases
30
+ super.concat([
31
+ {
32
+ existing_entry: {native_key: "id", e_plat_key: "id"}
33
+ },
34
+ {
35
+ existing_entry: {native_key: "topic", e_plat_key: "topic"}
36
+ },
37
+ {
38
+ alias_attribute: {native_key: "delivery_url", e_plat_key: "address"}
39
+ },
40
+ {
41
+ alias_attribute: {native_key: "date_created_gmt", e_plat_key: "created_at"}
42
+ },
43
+ {
44
+ alias_attribute: {native_key: "date_modified_gmt", e_plat_key: "updated_at"}
45
+ }
46
+ ])
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ module EPlat
2
+ module Paginated
3
+ class WooCommercePagination
4
+ attr_reader :next_link, :previous_link
5
+
6
+ def initialize(headers)
7
+ return unless headers
8
+
9
+ # WooCommerce uses X-WP-Total and X-WP-TotalPages headers for pagination info
10
+ # And link headers for next/prev links
11
+ @total = headers["X-WP-Total"].to_i if headers["X-WP-Total"]
12
+ @total_pages = headers["X-WP-TotalPages"].to_i if headers["X-WP-TotalPages"]
13
+
14
+ # Parse link headers
15
+ if headers["Link"]
16
+ parse_link_headers(headers["Link"])
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def parse_link_headers(link_header)
23
+ # Link headers look like:
24
+ # <https://example.com/wp-json/wc/v3/products?page=2>; rel="next", <https://example.com/wp-json/wc/v3/products?page=1>; rel="prev"
25
+ return unless link_header.is_a?(String)
26
+
27
+ links = link_header.split(",").map(&:strip)
28
+
29
+ links.each do |link|
30
+ if link =~ /<([^>]+)>;\s*rel="([^"]+)"/
31
+ url = $1
32
+ rel = $2
33
+
34
+ case rel
35
+ when "next"
36
+ @next_link = OpenStruct.new(url: url)
37
+ when "prev"
38
+ @previous_link = OpenStruct.new(url: url)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -38,17 +38,20 @@ module EPlat
38
38
  def add_to_instance!
39
39
  meta_programming_string =
40
40
  keys.map do |key|
41
+ # Sanitize the key to ensure it's a valid Ruby method name
42
+ method_name = key.to_s.gsub(/[^a-zA-Z0-9_]/, '_')
43
+
41
44
  <<-STRING
42
- def #{ key }
45
+ def #{ method_name }
43
46
  self.attributes['#{key}']
44
47
  end
45
48
 
46
- def #{key}=(value)
49
+ def #{method_name}=(value)
47
50
  self.attributes['#{key}'] = value
48
51
  end
49
52
 
50
- def #{ key }?
51
- ActiveModel::Type::Boolean.new.cast send '#{key}'
53
+ def #{ method_name }?
54
+ ActiveModel::Type::Boolean.new.cast send '#{method_name}'
52
55
  end
53
56
  STRING
54
57
  end.join("\n")
@@ -12,6 +12,14 @@ module EPlat
12
12
  self.site = "/" # this is overwritten below in initialize_singleton! when EPlat::Session is initialized
13
13
  add_response_method :full_response #full response of the request
14
14
 
15
+ PROTECTED_ATTRIBUTES = [
16
+ "self", "collection", "password", "api_key", "attributes",
17
+ "eval", "send", "public_send",
18
+ "class", "send", "destroy", "delete_all", "__send__", "__id__", "initialize", "method",
19
+ "delete", "delete_all", "destroy", "destroy_all", "update", "update_all", "save", "save_all",
20
+ "delete!", "delete_all!", "destroy!", "destroy_all!", "update!", "update_all!", "save!", "save_all!",
21
+ ].freeze
22
+
15
23
  class << self
16
24
  include Countable
17
25
 
@@ -96,6 +104,7 @@ module EPlat
96
104
  def initialize(attributes = {}, persisted = false)
97
105
  site = client.base_url
98
106
  ActiveResource::Base.include_root_in_json = client.shopify? && top_level_resource?
107
+ # attributes.reject!{ _1.starts_with? "_"} # remove private attributes, e.g. WooCommerce's '_links'
99
108
 
100
109
  super
101
110
 
@@ -119,9 +128,9 @@ module EPlat
119
128
  if client.shopify?
120
129
  @mapping.native_attributes.presence || schema.keys # EPlat uses Shopify's schema, apar from a couple of Graphql only fields
121
130
  elsif mapping.class.to_s != EPlat::Mapping::Base && @mapping.native_attributes.present?
122
- @mapping.native_attributes.presence
131
+ @mapping.native_attributes.presence - EPlat::Base::PROTECTED_ATTRIBUTES
123
132
  else
124
- attributes.keys
133
+ attributes.keys - EPlat::Base::PROTECTED_ATTRIBUTES
125
134
  end
126
135
  end
127
136
 
@@ -168,7 +177,7 @@ module EPlat
168
177
  def ensure_native_attributes!
169
178
  return if client.shopify? && EPlat.config.shopify_api_version == "2024_01"
170
179
 
171
- AttributeInterface.new(self, keys: native_keys)
180
+ # AttributeInterface.new(self, keys: native_keys)
172
181
  end
173
182
 
174
183
  def mapping_instance
@@ -9,7 +9,7 @@ module EPlat
9
9
  EPlat::Shopify::Product::Variant
10
10
  )
11
11
 
12
- def initialize(parsed = {})
12
+ def initialize(parsed = [])
13
13
  super parsed
14
14
  end
15
15
 
@@ -58,6 +58,9 @@ module EPlat
58
58
  if paginates_via_graphql?
59
59
  arg_name = (url == @next) ? "after" : "before"
60
60
  resource_class.find(:all, params: {arg_name => url, first: 100})
61
+ elsif client.woocommerce?
62
+ page_number = extract_page_from_url(url)
63
+ resource_class.find(:all, params: {page: page_number})
61
64
  else
62
65
  resource_class.all(from: url)
63
66
  end
@@ -80,6 +83,10 @@ module EPlat
80
83
  @pagination_links ||= EPlat::Paginated::LinkParams.new(
81
84
  link_params
82
85
  )
86
+ when :woocommerce
87
+ @pagination_links ||= EPlat::Paginated::LinkHeaders.new(
88
+ (full_response&.headers&.to_h || {})[:link]
89
+ )
83
90
  else
84
91
  raise "Unknown platform"
85
92
  end
@@ -107,7 +114,17 @@ module EPlat
107
114
  return request_data if paginates_via_graphql?
108
115
 
109
116
  query_params = URI.decode_www_form(URI(request_data).query).to_h
110
- query_params[client.pagination_param]
117
+
118
+ if client.woocommerce?
119
+ query_params["page"]
120
+ else
121
+ query_params[client.pagination_param]
122
+ end
123
+ end
124
+
125
+ def extract_page_from_url(url)
126
+ query_params = URI.decode_www_form(URI(url).query).to_h
127
+ query_params["page"]
111
128
  end
112
129
 
113
130
 
@@ -1,4 +1,3 @@
1
-
2
1
  module EPlat
3
2
  module Concerns
4
3
  module Aliases
@@ -31,6 +30,8 @@ module EPlat
31
30
 
32
31
  type_schema.each do |e_plat_key, type|
33
32
  next if processed[:getter].include?(e_plat_key)
33
+ # next if EPlat::Base::PROTECTED_ATTRIBUTES.include?(e_plat_key)
34
+
34
35
  add_to_instance! mapped_getter(e_plat_key), @is_virtual
35
36
  end
36
37
 
@@ -46,9 +47,11 @@ module EPlat
46
47
 
47
48
  def alias_mapped_getter(e_plat_key, native_key, proc: '->{_1}')
48
49
  proc_line = (proc) ? "current_value = #{ proc.strip }.call(current_value)" : nil
50
+ # Sanitize the key to ensure it's a valid Ruby method name
51
+ method_name = e_plat_key.to_s.gsub(/[^a-zA-Z0-9_]/, '_')
49
52
 
50
53
  <<-STRING
51
- def #{ e_plat_key }
54
+ def #{ method_name }
52
55
  current_value = #{ native_key_path(native_key) }
53
56
  #{ proc_line }
54
57
  type_coercer.type_value!('#{ e_plat_key }', current_value)
@@ -58,9 +61,11 @@ module EPlat
58
61
 
59
62
  def alias_mapped_setter(e_plat_key, native_key, proc: '->{_1}')
60
63
  proc_line = (proc) ? "new_value = #{ proc.strip }.call(new_value)" : nil
64
+ # Sanitize the key to ensure it's a valid Ruby method name
65
+ method_name = e_plat_key.to_s.gsub(/[^a-zA-Z0-9_]/, '_')
61
66
 
62
67
  <<-STRING
63
- def #{e_plat_key}=(value)
68
+ def #{method_name}=(value)
64
69
  new_value = value
65
70
  #{proc_line}
66
71
 
@@ -75,9 +80,11 @@ module EPlat
75
80
 
76
81
  def mapped_getter(e_plat_key, proc: '->{_1}')
77
82
  proc_line = (proc) ? "value = #{ proc.strip }.call(value)" : nil
83
+ # Sanitize the key to ensure it's a valid Ruby method name
84
+ method_name = e_plat_key.to_s.gsub(/[^a-zA-Z0-9_]/, '_')
78
85
 
79
86
  <<-STRING
80
- def #{ e_plat_key }
87
+ def #{ method_name }
81
88
  value = self.attributes['#{ e_plat_key }']
82
89
  #{ proc_line }
83
90
  type_coercer.type_value!('#{ e_plat_key }', value)
@@ -89,9 +96,11 @@ module EPlat
89
96
  # we dont want the eplat version of the value in change_attributes, we want the native version.
90
97
  def native_setter(native_key, proc: '->{_1}')
91
98
  proc_line = (proc) ? "value = #{ proc.strip }.call(value)" : nil
99
+ # Sanitize the key to ensure it's a valid Ruby method name
100
+ method_name = native_key.to_s.gsub(/[^a-zA-Z0-9_]/, '_')
92
101
 
93
102
  <<-STRING
94
- def #{native_key}=(value)
103
+ def #{method_name}=(value)
95
104
  #{proc_line}
96
105
  super
97
106
  attribute_will_change!('#{native_key}', force_value: value)
@@ -119,7 +128,6 @@ module EPlat
119
128
 
120
129
  def add_to_instance!(meta_programming_string, is_virtual=false)
121
130
  # puts meta_programming_string if meta_programming_string.include?('note')
122
-
123
131
  self.instance_eval { eval meta_programming_string }
124
132
  end
125
133
 
@@ -5,10 +5,19 @@ module EPlat
5
5
  module Metafieldable #< ActiveResource::CustomMethods
6
6
 
7
7
  def metafields(**options)
8
- Metafield.find(:all,
9
- from: current_resources_metafield_path,
10
- params: options
11
- )
8
+ if client.woocommerce?
9
+ meta_data.map do |m|
10
+ m.owner_id ||= id
11
+ m.owner_resource ||= self.class.element_name
12
+ m.owner = self
13
+ m
14
+ end
15
+ else
16
+ Metafield.find(:all,
17
+ from: current_resources_metafield_path,
18
+ params: options
19
+ )
20
+ end
12
21
  end
13
22
 
14
23
  def find_metafield(id)
@@ -18,19 +27,31 @@ module EPlat
18
27
  def add_metafield(metafield)
19
28
  raise ArgumentError, "You can only add metafields to a resource that has been saved" if new?
20
29
 
21
- metafield.owner_id = id
22
- metafield.owner_resource = self.class.element_name
23
- metafield.save
24
- metafield
30
+ metafield.owner_id ||= id
31
+ metafield.owner_resource ||= self.class.element_name
32
+
33
+ if client.woocommerce?
34
+ meta_data << metafield
35
+ save
36
+
37
+ meta_data.find{ _1.key == metafield.key }.then do |m|
38
+ m.owner_id = id
39
+ m.owner_resource = self.class.element_name
40
+ m.owner = self
41
+ m
42
+ end
43
+ else
44
+ metafield.save
45
+ metafield
46
+ end
25
47
  end
26
-
27
48
 
28
49
  private
29
50
 
30
51
  def current_resources_metafield_path
31
52
  uri = URI.parse(element_path)
32
53
  uri.path = uri.path.gsub(".json", "/metafields.json")
33
- uri.path += "/metafields" if uri.path.exclude?("json")
54
+ uri.path += "/metafields" if uri.path.exclude?("json")
34
55
  uri.path.gsub!('v2', 'v3') if client.bigcommerce? # metafield uses v3 API, even though orders are only available in v2
35
56
 
36
57
  uri.to_s
@@ -41,7 +41,7 @@ module EPlat
41
41
 
42
42
  add_root_if_needed(request_json, options[:root]).reject do |k,v|
43
43
  if v.is_a?(Array)
44
- v.reject(&:empty?).empty?
44
+ v.reject(&:empty?).empty? && k != "meta_data"
45
45
  else
46
46
  v.nil? || v.blank?
47
47
  end