spree_pluggto 0.0.1 → 1.0.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 (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