spree_pluggto 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/spree/admin/pluggto_fields_controller.rb +27 -0
  3. data/app/controllers/spree/admin/pluggto_settings_controller.rb +2 -1
  4. data/app/controllers/spree/api/v1/pluggto_controller.rb +30 -0
  5. data/app/jobs/spree_pluggto/order_created_job.rb +23 -0
  6. data/app/jobs/spree_pluggto/order_updated_job.rb +7 -0
  7. data/app/jobs/spree_pluggto/product_updated_job.rb +7 -0
  8. data/app/jobs/spree_pluggto/sku_deleted_job.rb +7 -0
  9. data/app/jobs/spree_pluggto/update_pluggto_order_job.rb +8 -0
  10. data/app/jobs/spree_pluggto/upsert_all_products_job.rb +1 -1
  11. data/app/jobs/spree_pluggto/upsert_product_job.rb +3 -3
  12. data/app/models/spree_pluggto/spree/product_decorator.rb +6 -3
  13. data/app/models/spree_pluggto/spree/shipment_decorator.rb +24 -0
  14. data/app/overrides/add_pluggto_id_to_order_summary.rb +14 -0
  15. data/app/overrides/add_pluggto_tab_to_order_sidebar.rb +11 -0
  16. data/app/services/spree_pluggto/{oauth.rb → api/oauth.rb} +1 -1
  17. data/app/services/spree_pluggto/api/order.rb +112 -0
  18. data/app/services/spree_pluggto/{product.rb → api/product.rb} +20 -16
  19. data/app/services/spree_pluggto/{request.rb → api/request.rb} +2 -2
  20. data/app/services/spree_pluggto/create_spree_order.rb +122 -0
  21. data/app/services/spree_pluggto/delete_spree_product_reference.rb +15 -0
  22. data/app/services/spree_pluggto/send_integration_errors.rb +24 -0
  23. data/app/services/spree_pluggto/update_spree_order.rb +50 -0
  24. data/app/services/spree_pluggto/update_spree_product.rb +17 -0
  25. data/app/views/spree/admin/pluggto_fields/index.html.erb +33 -0
  26. data/config/locales/pt-BR.yml +1 -0
  27. data/config/routes.rb +13 -0
  28. data/db/migrate/20210713194303_add_pluggto_id_to_spree_products.rb +5 -0
  29. data/db/migrate/20210805194730_add_pluggto_name_to_spree_products.rb +5 -0
  30. data/db/migrate/20210812182652_add_pluggto_id_to_spree_shipments.rb +5 -0
  31. data/db/migrate/20210812190431_add_sync_with_pluggto_to_products.rb +5 -0
  32. data/lib/spree_pluggto/version.rb +2 -2
  33. metadata +26 -6
  34. data/app/services/spree_pluggto/api.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ae3878fc284dd546b09e3727584623e83e05c22c2fac94dcfe93bda9f4c05e8
4
- data.tar.gz: 6b854eab6ca059e4da37b88736071e1ed487be9bb2cf41d5605ab9061b6ada09
3
+ metadata.gz: 7fe48703fbef832cd6c4fcf7336be85d018b872b44e6f299575ae2a24d04ee92
4
+ data.tar.gz: bc238a43d02ead868d093f66acec13b970f246cf04a24c66d4566382cd6abf6c
5
5
  SHA512:
6
- metadata.gz: 30a7cb6ff330b2afed6c6d5fbd12edd6f28a9f0b428711a1232b1e3ad37018750b88d5ec93ac8ab24b74d8c70ebd3b799a2148d442789969120633f234098c12
7
- data.tar.gz: 74e53fbb3d536b328b2366cf8d3ec7f02cb5e6a6dc3a603141f41893f12e9a732cf50b016be06450fc90f66daf1c92c1063cc5165ebabba295b1f4a047bd745f
6
+ metadata.gz: 3c1838f27d41d18720aec4a75c0de557f864f354bc87e16ee484d2e6627b34d61114ebafb11407b9f8ac42741499d3de33c5aa558a6e4220ae5639d753e50ecb
7
+ data.tar.gz: d831df2e340db48a77c3b3660bdc92449c87ee88ebadc2df4fdbb311943fb0d26fd0b80344280c76d63f1f43d60d112f1bf512de2f1545b6e368a830a8db0940
@@ -0,0 +1,27 @@
1
+ module Spree
2
+ module Admin
3
+ class PluggtoFieldsController < ResourceController
4
+ before_action :load_product
5
+
6
+ def index
7
+ end
8
+
9
+ def update
10
+ end
11
+
12
+ def location_after_save
13
+ admin_product_pluggto_fields_url(@product)
14
+ end
15
+
16
+ private
17
+
18
+ def load_product
19
+ @product = Spree::Product.friendly.find(params[:product_id])
20
+ end
21
+
22
+ def model_class
23
+ @model_class ||= Spree::Product
24
+ end
25
+ end
26
+ end
27
+ end
@@ -12,12 +12,13 @@ module Spree
12
12
 
13
13
  def update
14
14
  @pluggto_settings.update(pluggto_settings_params)
15
+ flash[:success] = Spree.t(:pluggto_settings_updated)
15
16
  redirect_to edit_admin_pluggto_settings_path
16
17
  end
17
18
 
18
19
  def upload_all_products
19
- flash[:success] = Spree.t(:pluggto_products_being_uploaded)
20
20
  ::SpreePluggto::UpsertAllProductsJob.perform_later
21
+ flash[:success] = Spree.t(:pluggto_products_being_uploaded)
21
22
  redirect_to edit_admin_pluggto_settings_path
22
23
  end
23
24
 
@@ -0,0 +1,30 @@
1
+ module Spree
2
+ module Api
3
+ module V1
4
+ class PluggtoController < Spree::Api::BaseController
5
+ skip_before_action :authenticate_user
6
+
7
+ # The post will be send in the following format:
8
+ # {"type":"PRODUCTS/SKUS/ORDERS","id":"PLUGGTO_ID","action":"UPDATEORCREATE","user":1120, "changes" : {"status" : false,"stock" : false,"price":false }}
9
+ #
10
+ # Example:
11
+ # { "user" : 129, "id" : "5b9169c309eacd415056aa3a", "changes" : { "status" : false, "stock" : false, "price" : false }, "type" : "products", "action" : "updated" }
12
+
13
+ def notifications
14
+ puts "Notification received from PluggTo: #{notification_params}"
15
+ service_class = "spree_pluggto/#{notification_params[:type].singularize}_#{notification_params[:action]}_job".camelize
16
+ puts "Service: #{service_class}"
17
+ service_class.constantize.perform_later(notification_params[:id])
18
+ head :ok
19
+ end
20
+
21
+ private
22
+
23
+ def notification_params
24
+ params.require(:pluggto).permit!
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ module SpreePluggto
2
+ class OrderCreatedJob < ActiveJob::Base
3
+
4
+
5
+ # sidekiq_retries_exhausted do |msg, ex|
6
+ # message = "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
7
+ # ::SpreePluggto::SendIntegrationErrors.new(msg['args']).call(message)
8
+ # end
9
+ # https://edgeguides.rubyonrails.org/active_job_basics.html#exceptions
10
+ # https://stackoverflow.com/questions/32193144/in-activejob-how-to-catch-any-exception
11
+ # https://github.com/mperham/sidekiq/issues/4496#issuecomment-600714253
12
+ # https://stackoverflow.com/questions/29085458/how-to-access-perform-parameters-in-activejob-rescue
13
+ rescue_from(StandardError) do |exception|
14
+ puts "--- Problem creating plugg_to order #{arguments} ---"
15
+ puts exception
16
+ ::SpreePluggto::SendIntegrationErrors.new(arguments.first).call(exception)
17
+ end
18
+
19
+ def perform(pluggto_id)
20
+ ::SpreePluggto::CreateSpreeOrder.new(pluggto_id).call
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ module SpreePluggto
2
+ class OrderUpdatedJob < ActiveJob::Base
3
+ def perform(pluggto_id)
4
+ ::SpreePluggto::UpdateSpreeOrder.new(pluggto_id).call
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module SpreePluggto
2
+ class ProductUpdatedJob < ActiveJob::Base
3
+ def perform(pluggto_id)
4
+ ::SpreePluggto::UpdateSpreeProduct.new(pluggto_id).call
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module SpreePluggto
2
+ class SkuDeletedJob < ActiveJob::Base
3
+ def perform(sku)
4
+ ::SpreePluggto::DeleteSpreeProductReference.new(sku).call
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module SpreePluggto
2
+ class UpdatePluggtoOrderJob < ActiveJob::Base
3
+ def perform(order_number)
4
+ spree_order = ::Spree::Order.find_by!(number: order_number)
5
+ ::SpreePluggto::Api::Order.update(spree_order)
6
+ end
7
+ end
8
+ end
@@ -1,7 +1,7 @@
1
1
  module SpreePluggto
2
2
  class UpsertAllProductsJob < ActiveJob::Base
3
3
  def perform
4
- ::Spree::Product.each do |product|
4
+ ::Spree::Product.active.where(sync_with_pluggto: true).each do |product|
5
5
  ::SpreePluggto::UpsertProductJob.perform_now(product.id)
6
6
  end
7
7
  end
@@ -1,9 +1,9 @@
1
1
  module SpreePluggto
2
- class UpsertProductJob < ApplicationJob
2
+ class UpsertProductJob < ActiveJob::Base
3
3
  # UPSERT => Updates the record if it exists, inserts if it is new
4
4
  def perform(product_id)
5
- product = Spree::Product.find!(product_id)
6
- SpreePluggto::Product.upsert(product)
5
+ product = ::Spree::Product.find(product_id)
6
+ ::SpreePluggto::Api::Product.upsert(product)
7
7
  end
8
8
  end
9
9
  end
@@ -1,15 +1,18 @@
1
1
  module SpreePluggto
2
2
  module Spree
3
3
  module ProductDecorator
4
+
5
+ # https://guides.spreecommerce.org/developer/customization/logic.html
6
+ # self.prepended is needed to access class-level methods, like has_many, scopes and callbacks
4
7
  def self.prepended(base)
5
- base.after_create :upsert_pluggto_product
6
- base.after_update :upsert_pluggto_product
8
+ base.after_create :upsert_pluggto_product, if: :sync_with_pluggto?
9
+ base.after_update :upsert_pluggto_product, if: :sync_with_pluggto?
7
10
  end
8
11
 
9
12
  private
10
13
 
11
14
  def upsert_pluggto_product
12
- ::SpreePluggto::UpsertProductJob.perform_later(pluggto_product)
15
+ ::SpreePluggto::UpsertProductJob.perform_later(self.id)
13
16
  end
14
17
 
15
18
  end
@@ -0,0 +1,24 @@
1
+ module SpreePluggto
2
+ module Spree
3
+ module ShipmentDecorator
4
+
5
+ # https://guides.spreecommerce.org/developer/customization/logic.html
6
+ # self.prepended is needed to access class-level methods, like has_many, scopes and callbacks
7
+ def self.prepended(base)
8
+ base.state_machine.after_transition to: :shipped, do: :update_pluggto_order, if: :pluggto_order?
9
+ end
10
+
11
+ private
12
+
13
+ def update_pluggto_order
14
+ ::SpreePluggto::UpdatePluggtoOrderJob.perform_later(order.number)
15
+ end
16
+
17
+ def pluggto_order?
18
+ order.channel == "pluggto"
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ Spree::Shipment.prepend(SpreePluggto::Spree::ShipmentDecorator)
@@ -0,0 +1,14 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/admin/shared/_order_summary',
3
+ name: 'add_pluggto_id_to_order_summary',
4
+ insert_bottom: '[id="order_tab_summary"]'
5
+ ) do
6
+ <<-HTML
7
+ <% if @order.pluggto_id %>
8
+ <tr>
9
+ <td><strong>Plugg.to id</strong></td>
10
+ <td><%= @order.pluggto_id %></td>
11
+ </tr>
12
+ <% end %>
13
+ HTML
14
+ end
@@ -0,0 +1,11 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/admin/shared/_product_tabs',
3
+ name: 'add_pluggto_tab_to_order_sidebar',
4
+ insert_bottom: '[data-hook="admin_product_tabs"]'
5
+ ) do
6
+ <<-HTML
7
+ <%= content_tag :li, class: ('active' if current == :pluggto_fields) do %>
8
+ <%= link_to_with_icon "transfer", "Plugg.to", spree.admin_product_pluggto_fields_url(@product) %>
9
+ <% end %>
10
+ HTML
11
+ end
@@ -1,4 +1,4 @@
1
- module SpreePluggto
1
+ module SpreePluggto::Api
2
2
  class Oauth
3
3
  attr_accessor :settings
4
4
 
@@ -0,0 +1,112 @@
1
+ module SpreePluggto::Api
2
+ class Order
3
+ class << self
4
+
5
+ def find(pluggto_id)
6
+ response = ::SpreePluggto::Api::Request.new.get("/orders/#{pluggto_id}")
7
+ response["Order"]
8
+ end
9
+
10
+ def update(spree_order)
11
+ response = ::SpreePluggto::Api::Request.new.put("/orders/#{spree_order.pluggto_id}", params(spree_order).to_json)
12
+ end
13
+
14
+ private
15
+
16
+ def pluggto_status(spree_order)
17
+ return 'canceled' if spree_order.canceled?
18
+ return 'shipping_informed' if spree_order.shipped?
19
+ return 'approved' if spree_order.shipment_state == 'ready'
20
+ return 'partial_payment' if spree_order.payment_state == 'credit_owed'
21
+ return 'pending'
22
+ end
23
+
24
+ def phone_area(number)
25
+ ddd_regex = /\((?<DDD>\d\d)\)/
26
+ ddd_regex.match(number)["DDD"]
27
+ end
28
+
29
+ def phone_without_area(number)
30
+ number.sub(/\(..\)/, '').strip
31
+ end
32
+
33
+ def params(spree_order)
34
+ {
35
+ "status": pluggto_status(spree_order),
36
+ "subtotal": spree_order.amount,
37
+ "total": spree_order.total,
38
+ "total_paid": spree_order.payment_total.to_s,
39
+ "shipping": spree_order.shipment_total,
40
+ "discount": spree_order.adjustment_total,
41
+ "external": spree_order.number,
42
+
43
+ "receiver_email": spree_order.email,
44
+ "receiver_name": spree_order.ship_address.firstname,
45
+ "receiver_lastname": spree_order.ship_address.lastname,
46
+ "receiver_address": spree_order.ship_address.address1,
47
+ "receiver_address_number": spree_order.ship_address.street_number,
48
+ "receiver_address_complement": spree_order.ship_address.address2,
49
+ "receiver_city": spree_order.ship_address.city,
50
+ "receiver_neighborhood": spree_order.ship_address.neighborhood,
51
+ "receiver_state": spree_order.ship_address.state.abbr,
52
+ "receiver_zipcode": spree_order.ship_address.zipcode,
53
+ "receiver_phone": phone_without_area(spree_order.ship_address.phone),
54
+ "receiver_phone_area": phone_area(spree_order.ship_address.phone),
55
+
56
+ "payer_email": spree_order.email,
57
+ "payer_name": spree_order.bill_address.firstname,
58
+ "payer_lastname": spree_order.bill_address.lastname,
59
+ "payer_address": spree_order.bill_address.address1,
60
+ "payer_address_number": spree_order.bill_address.street_number,
61
+ "payer_address_complement": spree_order.bill_address.address2,
62
+ "payer_city": spree_order.bill_address.city,
63
+ "payer_neighborhood": spree_order.bill_address.neighborhood,
64
+ "payer_state": spree_order.bill_address.state.abbr,
65
+ "payer_zipcode": spree_order.bill_address.zipcode,
66
+ "payer_phone": phone_without_area(spree_order.bill_address.phone),
67
+ "payer_phone_area": phone_area(spree_order.bill_address.phone),
68
+ "payer_cpf": spree_order.cpf,
69
+
70
+ "shipments": spree_order.shipments.map { |shipment|
71
+ {
72
+ "id": shipment.pluggto_id,
73
+ "estimate_delivery_date": (shipment.expected_delivery_date if shipment.shipped?),
74
+ "nfe_date": (shipment.shipped_at.to_date if shipment.shipped?),
75
+ "nfe_key": (shipment.get_invoice_key if shipment.shipped?),
76
+ "track_url": (shipment.tracking_url_with_code if shipment.shipped?),
77
+ "nfe_link": (shipment.get_invoice_pdf if shipment.shipped?),
78
+ "external": shipment.number,
79
+ "shipping_company": shipment.shipping_method.name,
80
+ "shipping_method": shipment.shipping_method.name,
81
+ "track_code": shipment.tracking,
82
+ "date_shipped": shipment.shipped_at&.to_date,
83
+ "nfe_number": shipment.nf_number&.split("/")&.first,
84
+ "nfe_serie": shipment.nf_number&.split("/")&.last,
85
+ "shipping_items": shipment.line_items.map { |line_item|
86
+ {
87
+ "sku": line_item.sku,
88
+ "quantity": line_item.quantity
89
+ }
90
+ }
91
+ }
92
+ },
93
+
94
+ "items": spree_order.line_items.map { |line_item|
95
+ {
96
+ "quantity": line_item.quantity,
97
+ "sku": line_item.sku,
98
+ "price": line_item.price,
99
+ "total": line_item.total,
100
+ "name": line_item.name,
101
+ "variation": {
102
+ "sku": line_item.sku
103
+ },
104
+ }
105
+ }
106
+
107
+ }.compact
108
+ end
109
+
110
+ end
111
+ end
112
+ end
@@ -1,31 +1,34 @@
1
- module SpreePluggto
1
+ module SpreePluggto::Api
2
2
  class Product
3
3
  class << self
4
4
 
5
- # UPSERT => Updates the record if it exists, inserts if it is new
6
- def upsert(product)
7
- SpreePluggto::Request.new.put("/skus/#{product.sku}", params(product).to_json)
5
+ def find(pluggto_id)
6
+ response = ::SpreePluggto::Api::Request.new.get("/products/#{pluggto_id}")
7
+ response["Product"]
8
8
  end
9
9
 
10
- def find(product)
11
- SpreePluggto::Request.new.get("/skus/#{product.sku}")
10
+ # UPSERT => Updates the record if it exists, inserts if it is a new record
11
+ def upsert(spree_product)
12
+ response = ::SpreePluggto::Api::Request.new.put("/skus/#{spree_product.sku}", params(spree_product).to_json)
13
+ spree_product.update_columns(pluggto_id: response.dig("Product","id"))
12
14
  end
13
-
15
+
14
16
  private
15
17
 
16
18
  def params(product)
19
+ description = ::ActionView::Helpers::TextHelper.simple_format(product.description) + "<br/><u>MAIS INFORMAÇÕES:</u><br/>".html_safe + product.info.html_safe
17
20
  {
18
21
  "sku": product.sku,
19
- "name": product.name,
20
- "special_price": product.on_sale? ? product.sale_price : nil,
22
+ "name": product.pluggto_name.present? ? product.pluggto_name : product.name,
23
+ "special_price": product.on_sale? ? product.sale_price : product.price,
21
24
  "price": product.price,
22
- "description": product.description,
23
- "brand": product.brand,
25
+ "description": description,
26
+ "brand": "Nordweg",
24
27
  "warranty_time": product.try(:months_of_warranty),
25
28
  "warranty_message": product.lifetime_warranty? ? "Garantia vitalícia" : "",
26
29
  "link": "#{::Rails.application.routes.url_helpers.spree_url}products/#{product.slug}",
27
30
  "categories": product.taxons.map { |taxon| {"name": taxon.name } },
28
- "handling_time": Spree::Config.try(:handling_time),
31
+ "handling_time": ::Spree::Config.try(:handling_time),
29
32
  "ean_not_mandatory": true,
30
33
  "dimension": {
31
34
  "length": product.depth,
@@ -36,8 +39,8 @@ module SpreePluggto
36
39
  "photos": product.images.map { |image|
37
40
  {
38
41
  "url": image.attachment.url(:big),
39
- "name": name,
40
- "title": name,
42
+ "name": product.name,
43
+ "title": product.name,
41
44
  "order": image.position,
42
45
  "external": image.attachment.url(:big)
43
46
  }
@@ -47,8 +50,9 @@ module SpreePluggto
47
50
  "sku": variant.sku,
48
51
  "name": variant.name,
49
52
  "quantity": variant.total_on_hand.finite? ? variant.total_on_hand : 99,
50
- "special_price": variant.product.on_sale? ? variant.product.sale_price : nil,
53
+ "special_price": variant.product.on_sale? ? variant.product.sale_price : variant.price,
51
54
  "price": variant.price,
55
+ "ean_not_mandatory": true,
52
56
  "attributes": variant.option_values.map { |option_value|
53
57
  {
54
58
  "code": option_value.option_type.name,
@@ -56,7 +60,7 @@ module SpreePluggto
56
60
  "value": { "code": option_value.name, "label": option_value.name }
57
61
  }
58
62
  },
59
- "photos": product.images.map { |image|
63
+ "photos": variant.images.map { |image|
60
64
  {
61
65
  "url": image.attachment.url(:big),
62
66
  "name": variant.name,
@@ -1,9 +1,9 @@
1
- module SpreePluggto
1
+ module SpreePluggto::Api
2
2
  class Request
3
3
  attr_reader :access_token
4
4
 
5
5
  def initialize
6
- @access_token = SpreePluggto::Oauth.new.get_token
6
+ @access_token = ::SpreePluggto::Api::Oauth.new.get_token
7
7
  end
8
8
 
9
9
  def get(path, body = {})
@@ -0,0 +1,122 @@
1
+ # Creates on Spree e new order after it was created on Pluggto
2
+ module SpreePluggto
3
+ class CreateSpreeOrder
4
+ attr_reader :pluggto_id
5
+
6
+ def initialize(pluggto_id)
7
+ @pluggto_id = pluggto_id
8
+ end
9
+
10
+ def call
11
+ # Skip creation if the order was already created on Spree
12
+ return if ::Spree::Order.find_by(pluggto_id: pluggto_id)
13
+
14
+ # Get info Plugg
15
+ pluggto_order = ::SpreePluggto::Api::Order.find(pluggto_id)
16
+
17
+ # Create the order on Spree
18
+ spree_order = ::Spree::Order.create(
19
+ channel: "pluggto",
20
+ pluggto_id: pluggto_order["id"],
21
+ user: ::Spree::User.find_by(email: pluggto_order["receiver_email"]),
22
+ email: pluggto_order["receiver_email"],
23
+ cpf: pluggto_order["receiver_cpf"] || pluggto_order["payer_cpf"],
24
+ )
25
+
26
+ # Add line items
27
+ pluggto_order["items"].each do |pluggto_item|
28
+ spree_order.line_items.new(
29
+ variant: ::Spree::Variant.find_by!(sku: pluggto_item["sku"]),
30
+ quantity: pluggto_item["quantity"],
31
+ price: pluggto_item["price"]
32
+ )
33
+ end
34
+
35
+ # Go to Addres
36
+ spree_order.next
37
+
38
+ # Add ship_address
39
+ spree_order.ship_address = ::Spree::Address.new(
40
+ firstname: pluggto_order["receiver_name"],
41
+ lastname: pluggto_order["receiver_lastname"],
42
+ address1: pluggto_order["receiver_address"],
43
+ address2: "#{pluggto_order["receiver_address_complement"]} - #{pluggto_order["receiver_address_reference"]}",
44
+ neighborhood: pluggto_order["receiver_neighborhood"],
45
+ street_number: pluggto_order["receiver_address_number"],
46
+ city: pluggto_order["receiver_city"],
47
+ zipcode: pluggto_order["receiver_zipcode"],
48
+ phone: "(#{pluggto_order['receiver_phone_area']}) #{pluggto_order['receiver_phone']}",
49
+ state_name: pluggto_order["receiver_state"],
50
+ state: ::Spree::State.find_by(abbr: pluggto_order["receiver_state"]),
51
+ alternative_phone: "(#{pluggto_order['receiver_phone2_area']}) #{pluggto_order['receiver_phone2']}",
52
+ country: ::Spree::Country.find_by(iso: "BR")
53
+ )
54
+
55
+ # Add bill_address
56
+ spree_order.bill_address = ::Spree::Address.new(
57
+ firstname: pluggto_order["payer_name"],
58
+ lastname: pluggto_order["payer_lastname"],
59
+ address1: pluggto_order["payer_address"],
60
+ address2: "#{pluggto_order["payer_address_complement"]} - #{pluggto_order["payer_address_reference"]}",
61
+ neighborhood: pluggto_order["payer_neighborhood"],
62
+ street_number: pluggto_order["payer_address_number"],
63
+ city: pluggto_order["payer_city"],
64
+ zipcode: pluggto_order["payer_zipcode"],
65
+ phone: "(#{pluggto_order['payer_phone_area']}) #{pluggto_order['payer_phone']}",
66
+ state_name: pluggto_order["payer_state"],
67
+ state: ::Spree::State.find_by(abbr: pluggto_order["payer_state"]),
68
+ alternative_phone: "(#{pluggto_order['payer_phone2_area']}) #{pluggto_order['payer_phone2']}",
69
+ country: ::Spree::Country.find_by(iso: "BR")
70
+ )
71
+
72
+ # Go to delivery
73
+ spree_order.next!
74
+
75
+ # Go to payment
76
+ spree_order.next!
77
+
78
+ # By calling 'next' the first shipping option was selected,
79
+ # we need to set it up according to what we received from Pluggto
80
+ spree_order.shipments.first.update_columns(
81
+ cost: pluggto_order["shipping"],
82
+ pluggto_id: pluggto_order.dig("shipments",0,"id")
83
+ )
84
+ spree_order.update_columns(
85
+ shipment_total: pluggto_order["shipping"]
86
+ )
87
+
88
+ # Add discounts
89
+ if pluggto_order["discount"].present? && pluggto_order["discount"] > 0
90
+ spree_order.adjustments.create(
91
+ order: spree_order,
92
+ label: "Desconto via Plugg.to",
93
+ amount: pluggto_order["discount"] * -1,
94
+ eligible: true
95
+ )
96
+ end
97
+
98
+ # Update the total after discounts
99
+ spree_order.update_totals
100
+
101
+ # Add payments
102
+ pluggto_order["payments"].each do |pluggto_payment|
103
+ spree_order.payments.create(
104
+ payment_method: ::Spree::PaymentMethod.find_by(type:"Spree::PaymentMethod::StoreCredit"), # Not ideal - we should define a specific payment method referring to PluggTo
105
+ installments: pluggto_payment["payment_installments"],
106
+ amount: pluggto_payment["payment_total"],
107
+ state: "completed"
108
+ )
109
+ end
110
+
111
+ # Completes the order
112
+ # The "Pending" on Pluggto is NOT "Paid", even if it has payments
113
+ # We should force the payments status according to the plugg_order status
114
+ spree_order.update_columns(
115
+ state: 'complete',
116
+ completed_at: DateTime.now,
117
+ payment_state: pluggto_order["status"] == 'approved' ? 'paid' : 'balance_due'
118
+ )
119
+ spree_order.fulfill! if spree_order.paid?
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,15 @@
1
+ # When a product is deleted on Plugg, we remove the pluggto_id reference on Spree
2
+ module SpreePluggto
3
+ class DeleteSpreeProductReference
4
+ attr_accessor :spree_product
5
+
6
+ def initialize(sku)
7
+ variant = ::Spree::Variant.find_by!(sku: sku)
8
+ @spree_product = variant.product
9
+ end
10
+
11
+ def call
12
+ spree_product.update_columns(pluggto_id: nil)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module SpreePluggto
2
+ class SendIntegrationErrors
3
+ attr_reader :pluggto_id
4
+
5
+ def initialize(pluggto_id)
6
+ @pluggto_id = pluggto_id
7
+ end
8
+
9
+ def call(error)
10
+ ::SpreePluggto::Api::Request.new.put("/orders/#{pluggto_id}", params(error).to_json)
11
+ end
12
+
13
+ def params(error)
14
+ {
15
+ "log_history": [
16
+ {
17
+ "message": "#{error}",
18
+ "date": "#{DateTime.now}"
19
+ }
20
+ ]
21
+ }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,50 @@
1
+ # Gets updates from an order on Pluggto and updates the order on Spree
2
+ module SpreePluggto
3
+ class UpdateSpreeOrder
4
+ attr_reader :pluggto_order
5
+ attr_accessor :spree_order
6
+
7
+ def initialize(pluggto_id)
8
+ @pluggto_order = ::SpreePluggto::Api::Order.find(pluggto_id)
9
+ @spree_order = ::Spree::Order.find_by!(pluggto_id: pluggto_id)
10
+ end
11
+
12
+ def call
13
+ case pluggto_order["status"]
14
+ when 'pending'
15
+ update_payments
16
+ when 'approved'
17
+ update_payments
18
+ set_as_paid
19
+ if !spree_order.shipped?
20
+ set_as_ready
21
+ spree_order.fulfill!
22
+ end
23
+ when 'canceled'
24
+ spree_order.update_columns(state: 'canceled')
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def update_payments
31
+ pluggto_order["payments"].each do |pluggto_payment|
32
+ spree_order.payments.find_or_create_by(
33
+ payment_method: ::Spree::PaymentMethod.find_by(type:"Spree::PaymentMethod::StoreCredit"), # Not ideal - we should define a specific payment method referring to PluggTo
34
+ amount: pluggto_payment["payment_total"],
35
+ installments: pluggto_payment["payment_installments"],
36
+ state: "completed"
37
+ )
38
+ end
39
+ end
40
+
41
+ def set_as_ready
42
+ spree_order.update_columns(shipment_state: 'ready')
43
+ end
44
+
45
+ def set_as_paid
46
+ spree_order.update_columns(payment_state: 'paid')
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,17 @@
1
+ # Gets updates from a product on Pluggto and updates the product on Spree
2
+ module SpreePluggto
3
+ class UpdateSpreeProduct
4
+ attr_reader :pluggto_product
5
+ attr_accessor :spree_product
6
+
7
+ def initialize(pluggto_id)
8
+ @pluggto_product = SpreePluggto::Api::Product.find(pluggto_id)
9
+ @spree_product = ::Spree::Product.find_by!(pluggto_id: pluggto_id)
10
+ end
11
+
12
+ def call
13
+ # Logic here to define what we want to update on Spree when PluggTo say a product was updated
14
+ # Only stock?
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ <%= render partial: 'spree/admin/shared/product_tabs', locals: { current: :pluggto_fields } %>
2
+
3
+ <%= form_for [:admin, @product], method: :put do |f| %>
4
+
5
+ <fieldset>
6
+ <div class="row">
7
+ <div class="col-xs-12 col-md-8" data-hook="admin_product_pluggto_fields">
8
+ <%= f.field_container :pluggto_id, class: ['form-group'] do %>
9
+ <%= f.label :sync_with_pluggto, "Sincronizar com Plugg.to" %>
10
+ <%= f.check_box :sync_with_pluggto %>
11
+ <%= f.error_message_on :sync_with_pluggto %>
12
+ <% end %>
13
+
14
+ <%= f.field_container :pluggto_name, class: ['form-group'] do %>
15
+ <%= f.label :pluggto_name, "Nome no Plugg.to" %>
16
+ <%= f.text_field :pluggto_name, class: 'form-control', placeholder: "Deixe em branco para usar o nome original do produto" %>
17
+ <%= f.error_message_on :pluggto_name %>
18
+ <% end %>
19
+
20
+ <%= f.field_container :pluggto_id, class: ['form-group'] do %>
21
+ <%= f.label :pluggto_id, "ID no Plugg.to" %>
22
+ <%= f.text_field :pluggto_id, class: 'form-control', readonly: true %>
23
+ <%= f.error_message_on :pluggto_id %>
24
+ <% end %>
25
+ </div>
26
+ </div>
27
+
28
+
29
+ <%= render partial: 'spree/admin/shared/edit_resource_links' %>
30
+
31
+ </fieldset>
32
+
33
+ <% end %>
@@ -6,3 +6,4 @@ pt-BR:
6
6
  spree:
7
7
  upload_all_products_to_pluggto: Enviar todos produtos para o Plugg.to
8
8
  pluggto_products_being_uploaded: Os produtos estão sendo enviados para o Plugg.to
9
+ pluggto_settings_updated: Configurações atualizadas
data/config/routes.rb CHANGED
@@ -3,5 +3,18 @@ Spree::Core::Engine.routes.draw do
3
3
  resource :pluggto_settings do
4
4
  get :upload_all_products
5
5
  end
6
+ resources :products do
7
+ resources :pluggto_fields, except: [:destroy]
8
+ end
9
+ end
10
+
11
+ namespace :api do
12
+ namespace :v1 do
13
+ namespace :pluggto, defaults: {format: :json} do
14
+ post :notifications
15
+ end
16
+ end
6
17
  end
18
+
19
+ # post "/pluggto/api/pluggto/notifications", to: 'api/v1/pluggto#notifications'
7
20
  end
@@ -0,0 +1,5 @@
1
+ class AddPluggtoIdToSpreeProducts < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :spree_products, :pluggto_id, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddPluggtoNameToSpreeProducts < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :spree_products, :pluggto_name, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddPluggtoIdToSpreeShipments < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :spree_shipments, :pluggto_id, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddSyncWithPluggtoToProducts < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :spree_products, :sync_with_pluggto, :boolean, default: false
4
+ end
5
+ end
@@ -8,9 +8,9 @@ module SpreePluggto
8
8
  end
9
9
 
10
10
  module VERSION
11
- MAJOR = 0
11
+ MAJOR = 1
12
12
  MINOR = 0
13
- TINY = 1
13
+ TINY = 0
14
14
  # PRE = 'alpha'.freeze
15
15
 
16
16
  STRING = [MAJOR, MINOR, TINY].compact.join('.')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_pluggto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Kuhn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-13 00:00:00.000000000 Z
11
+ date: 2021-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree_core
@@ -280,22 +280,42 @@ files:
280
280
  - app/assets/javascripts/spree/frontend/spree_pluggto.js
281
281
  - app/assets/stylesheets/spree/backend/spree_pluggto.css
282
282
  - app/assets/stylesheets/spree/frontend/spree_pluggto.css
283
+ - app/controllers/spree/admin/pluggto_fields_controller.rb
283
284
  - app/controllers/spree/admin/pluggto_settings_controller.rb
285
+ - app/controllers/spree/api/v1/pluggto_controller.rb
286
+ - app/jobs/spree_pluggto/order_created_job.rb
287
+ - app/jobs/spree_pluggto/order_updated_job.rb
288
+ - app/jobs/spree_pluggto/product_updated_job.rb
289
+ - app/jobs/spree_pluggto/sku_deleted_job.rb
290
+ - app/jobs/spree_pluggto/update_pluggto_order_job.rb
284
291
  - app/jobs/spree_pluggto/upsert_all_products_job.rb
285
292
  - app/jobs/spree_pluggto/upsert_product_job.rb
286
293
  - app/models/pluggto_settings.rb
287
294
  - app/models/spree_pluggto/spree/product_decorator.rb
295
+ - app/models/spree_pluggto/spree/shipment_decorator.rb
296
+ - app/overrides/add_pluggto_id_to_order_summary.rb
297
+ - app/overrides/add_pluggto_tab_to_order_sidebar.rb
288
298
  - app/overrides/add_settings_to_admin_configurations.rb
289
- - app/services/spree_pluggto/api.rb
290
- - app/services/spree_pluggto/oauth.rb
291
- - app/services/spree_pluggto/product.rb
292
- - app/services/spree_pluggto/request.rb
299
+ - app/services/spree_pluggto/api/oauth.rb
300
+ - app/services/spree_pluggto/api/order.rb
301
+ - app/services/spree_pluggto/api/product.rb
302
+ - app/services/spree_pluggto/api/request.rb
303
+ - app/services/spree_pluggto/create_spree_order.rb
304
+ - app/services/spree_pluggto/delete_spree_product_reference.rb
305
+ - app/services/spree_pluggto/send_integration_errors.rb
306
+ - app/services/spree_pluggto/update_spree_order.rb
307
+ - app/services/spree_pluggto/update_spree_product.rb
308
+ - app/views/spree/admin/pluggto_fields/index.html.erb
293
309
  - app/views/spree/admin/pluggto_settings/edit.html.erb
294
310
  - bin/rails
295
311
  - config/locales/en.yml
296
312
  - config/locales/pt-BR.yml
297
313
  - config/routes.rb
298
314
  - db/migrate/20210706173803_create_pluggto_settings.rb
315
+ - db/migrate/20210713194303_add_pluggto_id_to_spree_products.rb
316
+ - db/migrate/20210805194730_add_pluggto_name_to_spree_products.rb
317
+ - db/migrate/20210812182652_add_pluggto_id_to_spree_shipments.rb
318
+ - db/migrate/20210812190431_add_sync_with_pluggto_to_products.rb
299
319
  - lib/generators/spree_pluggto/install/install_generator.rb
300
320
  - lib/spree_pluggto.rb
301
321
  - lib/spree_pluggto/engine.rb
@@ -1,15 +0,0 @@
1
- module SpreePluggto
2
- class Api
3
- def find_product(spree_product)
4
- SpreePluggto::Request.new.get("/products/{pluggto_product_id}")
5
- end
6
-
7
- def upset_product(spree_product)
8
- SpreePluggto::Request.new.put("/skus/#{product.sku}", product.pluggto_product.to_json)
9
- end
10
-
11
- def upsert_variant(spree_variant)
12
- SpreePluggto::Request.new.put("/skus/#{spree_variant.sku}", body)
13
- end
14
- end
15
- end