solidus_me 3.6.1 → 3.7.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.
- checksums.yaml +4 -4
- data/README.md +151 -29
- data/app/controller/spree/admin/orders/labels_controller.rb +124 -0
- data/app/controller/spree/admin/solidus_me/accounts_controller.rb +7 -9
- data/app/models/solidus_me/account.rb +89 -43
- data/app/models/solidus_me/label.rb +155 -0
- data/app/models/solidus_me/me_client.rb +47 -0
- data/app/models/solidus_me/melhor_envio.rb +18 -140
- data/app/models/solidus_me/package_estimator.rb +22 -0
- data/app/models/solidus_me/rate_calculator.rb +37 -0
- data/app/views/spree/admin/orders/labels/_steps.html.erb +78 -0
- data/app/views/spree/admin/orders/labels/index.html.erb +28 -0
- data/app/views/spree/admin/orders/labels/show.html.erb +46 -0
- data/app/views/spree/admin/orders/labels/step_generate.html.erb +48 -0
- data/app/views/spree/admin/orders/labels/step_payment.html.erb +83 -0
- data/app/views/spree/admin/orders/labels/step_print.html.erb +48 -0
- data/app/views/spree/admin/solidus_me/accounts/_form.html.erb +14 -3
- data/app/views/spree/admin/solidus_me/accounts/index.html.erb +11 -6
- data/config/routes.rb +9 -0
- data/db/migrate/20250801130502_rename_column_token_expires_in.rb +5 -0
- data/db/migrate/20250801130700_add_column_test_mode.rb +5 -0
- data/db/migrate/20250801142036_create_solidus_me_labels.rb +16 -0
- data/db/migrate/20250801170700_add_last_synced_at_to_solidus_me_accounts.rb +5 -0
- data/db/migrate/20250801174106_add_timestamps_to_labels.rb +6 -0
- data/lib/generators/solidus_me/install/install_generator.rb +4 -0
- data/lib/generators/solidus_me/install/templates/app/overrides/spree_order_solidus_me_labels.rb +9 -0
- data/lib/solidus_me/version.rb +1 -1
- metadata +35 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa89482d312023371ec4e9fd7460f58d6ba9a840fb1decb3caa3baf3c373a49e
|
4
|
+
data.tar.gz: cef322e476abd32180ef4e10c46943de02c93a92695be5786588574544a5e45e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b0ec3d830d746dc02ec25201ab0ab316b4e4ccc82ba96eee3a6e4ca61d8e948149b3b522883a3f136e3004a7a0fd7026c851c0861b2a0cd7e42d2b3fcff1ab8
|
7
|
+
data.tar.gz: f9066b9fc94c55981f93d4785636148729e083cb8a0f2acaa469bb1e048b9d2792a8b14956a41529c835c2a34fa7b9c2ab3aa464a4b857c1c154f4e10e44822d
|
data/README.md
CHANGED
@@ -1,54 +1,176 @@
|
|
1
|
-
#
|
1
|
+
# SolidusMe
|
2
2
|
|
3
|
-
Gem
|
3
|
+
[](https://badge.fury.io/rb/solidus_me)
|
4
4
|
|
5
|
-
|
5
|
+
Extensão do Solidus para integração com a API do [Melhor Envio](https://melhorenvio.com.br/), permitindo:
|
6
6
|
|
7
|
-
|
7
|
+
- Cálculo de frete em tempo real
|
8
|
+
- Geração de etiquetas de envio
|
9
|
+
- Gerenciamento de contas do Melhor Envio
|
10
|
+
- Interface administrativa para controle de etiquetas
|
11
|
+
|
12
|
+
## Requisitos
|
13
|
+
|
14
|
+
- Ruby >= 2.7
|
15
|
+
- Solidus >= 3.0
|
16
|
+
- Rails >= 6.0
|
17
|
+
|
18
|
+
## Instalação
|
19
|
+
|
20
|
+
Adicione esta linha ao Gemfile da sua aplicação:
|
8
21
|
|
9
22
|
```ruby
|
10
23
|
gem 'solidus_me'
|
11
24
|
```
|
12
25
|
|
13
|
-
|
26
|
+
Execute:
|
27
|
+
|
28
|
+
```bash
|
29
|
+
$ bundle install
|
30
|
+
```
|
31
|
+
|
32
|
+
Execute o gerador de instalação:
|
33
|
+
|
34
|
+
```bash
|
35
|
+
$ rails generate solidus_me:install
|
36
|
+
```
|
37
|
+
|
38
|
+
Execute as migrações:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
$ rails db:migrate
|
42
|
+
```
|
43
|
+
|
44
|
+
## Dependências
|
45
|
+
|
46
|
+
Esta gem depende de outras gems que precisam ser configuradas antes do uso:
|
47
|
+
|
48
|
+
### 1. SolidusTecEstimator
|
49
|
+
|
50
|
+
Execute o gerador de instalação:
|
51
|
+
|
52
|
+
```bash
|
53
|
+
$ rails generate solidus_tec_estimator:install
|
54
|
+
```
|
55
|
+
|
56
|
+
Siga as instruções de configuração da gem **[solidus_tec_estimator](https://github.com/todasessascoisas/solidus_tec_estimator)**.
|
57
|
+
|
58
|
+
### 2. SolidusBrazilianAdaptations
|
59
|
+
|
60
|
+
Execute o gerador de instalação:
|
61
|
+
|
62
|
+
```bash
|
63
|
+
$ rails generate solidus_brazilian_adaptations:install
|
64
|
+
```
|
65
|
+
|
66
|
+
Siga as instruções de configuração da gem **[solidus_brazilian_adaptations](https://github.com/todasessascoisas/solidus_brazilian_adaptations)**.
|
67
|
+
|
68
|
+
## Configuração
|
69
|
+
|
70
|
+
### 1. Configuração da Conta do Melhor Envio
|
71
|
+
|
72
|
+
Acesse o painel administrativo do Solidus e navegue até **Configurações > Contas Melhor Envio** para configurar suas credenciais da API.
|
14
73
|
|
15
|
-
|
16
|
-
|
17
|
-
|
74
|
+
### 2. Configuração do Provider de Frete
|
75
|
+
|
76
|
+
Configure o **TecEstimator** ou outro provider compatível para usar o "Melhor Envio" como provedor de frete.
|
77
|
+
|
78
|
+
### 3. Configuração da Interface de Etiquetas
|
79
|
+
|
80
|
+
Para exibir a aba "Etiqueta" nas ordens do painel administrativo, você precisa adicionar o seguinte código ao arquivo `app/views/spree/admin/shared/_order_submenu.html.erb`:
|
81
|
+
|
82
|
+
```erb
|
83
|
+
<% if @order.completed? %>
|
84
|
+
<% provider_id = @order.shipments.sole.selected_shipping_rate.shipping_method.provider_id %>
|
85
|
+
<% if provider_id && SolidusTecEstimator::Provider.find(provider_id).name == "Melhor Envio" %>
|
86
|
+
<% label = SolidusMe::Label.find_by(spree_order_id: @order.id) %>
|
87
|
+
<li class="tab" data-hook='admin_order_tabs_return_authorizations'>
|
88
|
+
<% if label %>
|
89
|
+
<a href="<%= admin_orders_label_path(order_number: @order.number, id: label.id) %>">Etiqueta</a>
|
90
|
+
<% else %>
|
91
|
+
<a href="<%= admin_orders_labels_path(order_number: @order.number) %>">Etiqueta</a>
|
92
|
+
<% end %>
|
93
|
+
</li>
|
94
|
+
<% end %>
|
95
|
+
<% end %>
|
18
96
|
```
|
19
97
|
|
20
|
-
|
98
|
+
**Importante:** Se o arquivo `app/views/spree/admin/shared/_order_submenu.html.erb` não existir na sua aplicação, você deve criá-lo copiando o arquivo original do Solidus:
|
99
|
+
|
100
|
+
👉 **[Baixar arquivo original do Solidus](https://github.com/solidusio/solidus/blob/main/backend/app/views/spree/admin/shared/_order_submenu.html.erb)**
|
101
|
+
|
102
|
+
Após baixar, coloque o arquivo no caminho correto da sua aplicação e adicione o código da aba de etiqueta.
|
103
|
+
|
104
|
+
## Funcionalidades
|
105
|
+
|
106
|
+
### Gerenciamento de Contas
|
107
|
+
|
108
|
+
- **Múltiplas contas**: Suporte a contas de teste e produção
|
109
|
+
- **Autenticação OAuth2**: Integração segura com a API do Melhor Envio
|
110
|
+
- **Sincronização automática**: Atualização de saldos e informações da conta
|
111
|
+
|
112
|
+
### Etiquetas de Envio
|
113
|
+
|
114
|
+
- **Geração de etiquetas**: Criação automática de etiquetas após finalização do pedido
|
115
|
+
- **Rastreamento**: Acompanhamento do status de entrega
|
116
|
+
- **Impressão**: Interface para impressão de etiquetas
|
117
|
+
- **Histórico**: Controle completo do ciclo de vida das etiquetas
|
118
|
+
|
119
|
+
### Interface Administrativa
|
120
|
+
|
121
|
+
- **Dashboard de contas**: Visualização de saldos e status das contas
|
122
|
+
- **Gestão de etiquetas**: Interface completa para gerenciar etiquetas por pedido
|
123
|
+
- **Configurações**: Painel de configuração das integrações
|
124
|
+
|
125
|
+
## Modelos
|
21
126
|
|
22
|
-
|
23
|
-
|
127
|
+
### SolidusMe::Account
|
128
|
+
|
129
|
+
Representa uma conta do Melhor Envio configurada no sistema.
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
# Buscar conta ativa em modo de teste
|
133
|
+
account = SolidusMe::Account.first_active_test_mode
|
134
|
+
|
135
|
+
# Verificar saldo da conta
|
136
|
+
balance = account.get_balance
|
137
|
+
|
138
|
+
# Obter dados da conta
|
139
|
+
account_data = account.get_account_data
|
24
140
|
```
|
25
141
|
|
26
|
-
|
142
|
+
### SolidusMe::Label
|
27
143
|
|
28
|
-
|
144
|
+
Representa uma etiqueta de envio gerada para um pedido.
|
29
145
|
|
30
146
|
```ruby
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
147
|
+
# Buscar etiqueta por pedido
|
148
|
+
label = SolidusMe::Label.find_by(spree_order_id: order.id)
|
149
|
+
|
150
|
+
# Verificar status da etiqueta
|
151
|
+
puts label.status
|
36
152
|
```
|
37
153
|
|
38
|
-
|
154
|
+
## Configuração Avançada
|
39
155
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
156
|
+
### Inicializador
|
157
|
+
|
158
|
+
O gerador cria um arquivo de configuração em `config/initializers/solidus_me.rb`:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
SolidusMe.configure do |config|
|
162
|
+
# Suas configurações personalizadas
|
163
|
+
end
|
46
164
|
```
|
47
|
-
Após salvar, o link completo para autenticação do aplicativo ficará disponível abaixo. A gem disponibiliza um endpoint (`HOST/admin/melhor_envio/authorize`) para receber o code e realizar a autenticação automaticamente. Uma vez autorizado, são gerados os `refresh_token` e `access_token`, e o sistema estará pronto para cotação dos fretes junto ao Melhor Envio.
|
48
165
|
|
49
|
-
|
166
|
+
### Rotas
|
167
|
+
|
168
|
+
As rotas são automaticamente montadas na aplicação:
|
50
169
|
|
51
170
|
```ruby
|
52
|
-
#
|
53
|
-
|
171
|
+
# config/routes.rb
|
172
|
+
Rails.application.routes.draw do
|
173
|
+
mount SolidusMe::Engine => "/solidus_me"
|
174
|
+
# suas outras rotas...
|
175
|
+
end
|
54
176
|
```
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
module Orders
|
4
|
+
class LabelsController < BaseController
|
5
|
+
before_action :load_order
|
6
|
+
before_action :set_label, only: [:show, :update, :step_payment, :step_generate, :step_print]
|
7
|
+
|
8
|
+
def index
|
9
|
+
@current_step = 1
|
10
|
+
labels = order_labels.recent
|
11
|
+
if labels.present?
|
12
|
+
@label = labels.first
|
13
|
+
redirect_to admin_orders_label_path(@order.number, @label.id)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def show
|
18
|
+
@current_step = @label.current_step
|
19
|
+
|
20
|
+
unless @label.status == "completed_label"
|
21
|
+
redirect_to step_path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def step_payment
|
26
|
+
@balance = current_account.get_balance&.balance
|
27
|
+
@current_step = 2
|
28
|
+
end
|
29
|
+
|
30
|
+
def step_generate
|
31
|
+
@current_step = 3
|
32
|
+
end
|
33
|
+
|
34
|
+
def step_print
|
35
|
+
@current_step = 4
|
36
|
+
end
|
37
|
+
|
38
|
+
def create
|
39
|
+
@label = ::SolidusMe::Label.find_or_initialize_by(
|
40
|
+
spree_order_id: @order.id,
|
41
|
+
solidus_me_account_id: current_account.id,
|
42
|
+
status: "ready_to_add_to_cart"
|
43
|
+
)
|
44
|
+
|
45
|
+
@label.add_to_cart!
|
46
|
+
flash[:success] = "Etiqueta criada e adicionada ao carrinho com sucesso"
|
47
|
+
redirect_to admin_orders_step_payment_label_path(@order.number, @label.id)
|
48
|
+
rescue StandardError => e
|
49
|
+
Rails.logger.error "Failed to create label for order #{@order.number}: #{e.message}"
|
50
|
+
flash[:error] = "Erro ao processar etiqueta: #{e.message}"
|
51
|
+
redirect_to admin_orders_labels_path(@order.number)
|
52
|
+
end
|
53
|
+
|
54
|
+
def update
|
55
|
+
case @label.status
|
56
|
+
when "pending"
|
57
|
+
process_payment
|
58
|
+
when "paid"
|
59
|
+
process_generation
|
60
|
+
when "generated_label"
|
61
|
+
process_printing
|
62
|
+
else
|
63
|
+
flash[:error] = "Ação não permitida para status atual"
|
64
|
+
redirect_to admin_orders_label_path(@order.number, @label.id)
|
65
|
+
end
|
66
|
+
rescue StandardError => e
|
67
|
+
flash[:error] = "Erro ao processar: #{e.message}"
|
68
|
+
redirect_to admin_orders_label_path(@order.number, @label.id)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def load_order
|
74
|
+
@order = Spree::Order.find_by!(number: params[:order_number])
|
75
|
+
end
|
76
|
+
|
77
|
+
def set_label
|
78
|
+
@label = order_labels.find(params[:id])
|
79
|
+
end
|
80
|
+
|
81
|
+
def order_labels
|
82
|
+
@order.solidus_me_labels
|
83
|
+
end
|
84
|
+
|
85
|
+
def current_account
|
86
|
+
@current_account ||= ::SolidusMe::Account.active.first
|
87
|
+
end
|
88
|
+
|
89
|
+
def step_path
|
90
|
+
case @label.status
|
91
|
+
when "pending"
|
92
|
+
admin_orders_step_payment_label_path(@order.number, @label.id)
|
93
|
+
when "paid"
|
94
|
+
admin_orders_step_generate_label_path(@order.number, @label.id)
|
95
|
+
when "generated_label"
|
96
|
+
admin_orders_step_print_label_path(@order.number, @label.id)
|
97
|
+
when "completed_label"
|
98
|
+
admin_orders_label_path(@order.number, @label.id)
|
99
|
+
else
|
100
|
+
admin_orders_labels_path(@order.number)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def process_payment
|
105
|
+
@label.pay!
|
106
|
+
flash[:success] = "Etiqueta paga com sucesso"
|
107
|
+
redirect_to admin_orders_step_generate_label_path(@order.number, @label.id)
|
108
|
+
end
|
109
|
+
|
110
|
+
def process_generation
|
111
|
+
@label.generate!
|
112
|
+
flash[:success] = "Etiqueta gerada com sucesso"
|
113
|
+
redirect_to admin_orders_step_print_label_path(@order.number, @label.id)
|
114
|
+
end
|
115
|
+
|
116
|
+
def process_printing
|
117
|
+
@label.print!
|
118
|
+
flash[:success] = "Link de impressão gerado com sucesso"
|
119
|
+
redirect_to admin_orders_label_path(@order.number, @label.id)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -44,22 +44,20 @@ module Spree
|
|
44
44
|
def authorize
|
45
45
|
code = params[:code]
|
46
46
|
me_account = ::SolidusMe::Account.first
|
47
|
-
|
48
|
-
client_id: me_account.client_id,
|
49
|
-
client_secret: me_account.client_secret,
|
47
|
+
authorize_response = MeApi::Client.new(client_id: me_account.client_id, client_secret: me_account.client_secret).authorize(
|
50
48
|
code: code,
|
51
49
|
redirect_url: me_account.redirect_url
|
52
|
-
)
|
50
|
+
)
|
53
51
|
me_account.update(
|
54
|
-
access_token:
|
55
|
-
refresh_token:
|
56
|
-
|
52
|
+
access_token: authorize_response.access_token,
|
53
|
+
refresh_token: authorize_response.refresh_token,
|
54
|
+
token_expires_at: (DateTime.now + authorize_response.expires_in.seconds).to_s
|
57
55
|
)
|
58
56
|
redirect_to edit_admin_solidus_me_account_path me_account
|
59
57
|
end
|
60
58
|
|
61
59
|
def update_from_api
|
62
|
-
@me_account.
|
60
|
+
@me_account.sync_with_api!
|
63
61
|
flash[:success] = "Dados da conta atualizados a partir da API"
|
64
62
|
redirect_to edit_admin_solidus_me_account_path(@me_account.id)
|
65
63
|
rescue StandardError => e
|
@@ -71,7 +69,7 @@ module Spree
|
|
71
69
|
|
72
70
|
def account_params
|
73
71
|
params.require(:account).permit(
|
74
|
-
:client_id, :client_secret, :access_token, :refresh_token, :redirect_url, :state, :
|
72
|
+
:client_id, :client_secret, :access_token, :refresh_token, :redirect_url, :state, :token_expires_at, :services, :postal_code_from, :name, :email, :tax_id, :phone, :address, :address_complement, :address_number, :address_district, :address_city, :address_state_abbr, :test_mode
|
75
73
|
)
|
76
74
|
end
|
77
75
|
|
@@ -1,53 +1,99 @@
|
|
1
1
|
module SolidusMe
|
2
2
|
class Account < ApplicationRecord
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
def
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
def
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
3
|
+
has_many :labels, class_name: "SolidusMe::Label", foreign_key: :solidus_me_account_id, dependent: :destroy
|
4
|
+
|
5
|
+
validates :client_id, :client_secret, presence: true
|
6
|
+
validate :only_one_production_account_active, if: :production_mode?
|
7
|
+
|
8
|
+
scope :active, -> { where.not(access_token: [nil, ""]) }
|
9
|
+
scope :production_mode, -> { where(test_mode: false) }
|
10
|
+
scope :test_mode, -> { where(test_mode: true) }
|
11
|
+
|
12
|
+
scope :first_active_test_mode, -> { test_mode.active.first }
|
13
|
+
scope :first_active_production_mode, -> { production_mode.active.first }
|
14
|
+
|
15
|
+
delegate :get_account_data, :get_balance, to: :me_client
|
16
|
+
|
17
|
+
def active?
|
18
|
+
access_token.present?
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_mode?
|
22
|
+
test_mode
|
23
|
+
end
|
24
|
+
|
25
|
+
def production_mode?
|
26
|
+
!test_mode?
|
27
|
+
end
|
28
|
+
|
29
|
+
def address_complete?
|
30
|
+
[address, address_city, address_state_abbr, postal_code_from].all?(&:present?)
|
31
|
+
end
|
32
|
+
|
33
|
+
def mode_display
|
34
|
+
test_mode? ? "Teste" : "Produção"
|
35
|
+
end
|
36
|
+
|
37
|
+
def status_display
|
38
|
+
if active?
|
39
|
+
"Ativa (#{mode_display})"
|
40
|
+
else
|
41
|
+
"Inativa"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def sync_with_api!
|
46
|
+
transaction do
|
47
|
+
api_data = get_account_data
|
48
|
+
sync_with_api_data(api_data)
|
49
|
+
touch(:last_synced_at)
|
50
|
+
end
|
51
|
+
rescue StandardError => e
|
52
|
+
Rails.logger.error "Failed to sync account #{id}: #{e.message}"
|
53
|
+
raise
|
45
54
|
end
|
46
55
|
|
47
56
|
private
|
48
57
|
|
49
58
|
def me_client
|
50
|
-
@me_client ||=
|
59
|
+
@me_client ||= MeClient.for_account(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
def sync_profile_data(api_data)
|
63
|
+
assign_attributes(
|
64
|
+
name: api_data.name,
|
65
|
+
email: api_data.email,
|
66
|
+
tax_id: api_data.document,
|
67
|
+
phone: api_data.phone&.phone
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def sync_address_data(api_address)
|
72
|
+
return if api_address.nil?
|
73
|
+
|
74
|
+
assign_attributes(
|
75
|
+
address: api_address.address,
|
76
|
+
address_complement: api_address.complement,
|
77
|
+
address_number: api_address.number,
|
78
|
+
address_district: api_address.district,
|
79
|
+
address_city: api_address.city&.city,
|
80
|
+
address_state_abbr: api_address.city&.state&.state_abbr,
|
81
|
+
postal_code_from: api_address.postal_code
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def sync_with_api_data(api_data)
|
86
|
+
sync_profile_data(api_data)
|
87
|
+
sync_address_data(api_data.address)
|
88
|
+
end
|
89
|
+
|
90
|
+
def only_one_production_account_active
|
91
|
+
return unless access_token.present? && production_mode?
|
92
|
+
|
93
|
+
existing_production = self.class.production_mode.active.where.not(id: id)
|
94
|
+
if existing_production.exists?
|
95
|
+
errors.add(:test_mode, "Apenas uma conta de produção pode estar ativa por vez")
|
96
|
+
end
|
51
97
|
end
|
52
98
|
end
|
53
99
|
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module SolidusMe
|
2
|
+
class Label < ApplicationRecord
|
3
|
+
belongs_to :order, foreign_key: :spree_order_id, class_name: "::Spree::Order"
|
4
|
+
belongs_to :account, foreign_key: :solidus_me_account_id, class_name: "SolidusMe::Account"
|
5
|
+
|
6
|
+
validates :status, presence: true
|
7
|
+
|
8
|
+
scope :pending, -> { where(status: 'pending') }
|
9
|
+
scope :paid, -> { where(status: 'paid') }
|
10
|
+
scope :generated, -> { where(status: 'generated_label') }
|
11
|
+
scope :completed, -> { where(status: 'completed_label') }
|
12
|
+
scope :recent, -> { order(created_at: :desc) }
|
13
|
+
|
14
|
+
def pending?
|
15
|
+
status == 'pending'
|
16
|
+
end
|
17
|
+
|
18
|
+
def paid?
|
19
|
+
status == 'paid'
|
20
|
+
end
|
21
|
+
|
22
|
+
def generated?
|
23
|
+
status == 'generated_label'
|
24
|
+
end
|
25
|
+
|
26
|
+
def completed?
|
27
|
+
status == 'completed_label'
|
28
|
+
end
|
29
|
+
|
30
|
+
def can_pay?
|
31
|
+
pending?
|
32
|
+
end
|
33
|
+
|
34
|
+
def can_generate?
|
35
|
+
paid?
|
36
|
+
end
|
37
|
+
|
38
|
+
def can_print?
|
39
|
+
generated?
|
40
|
+
end
|
41
|
+
|
42
|
+
def current_step
|
43
|
+
case status
|
44
|
+
when "pending"
|
45
|
+
2
|
46
|
+
when "paid"
|
47
|
+
3
|
48
|
+
when "generated_label"
|
49
|
+
4
|
50
|
+
when "completed_label"
|
51
|
+
5
|
52
|
+
else
|
53
|
+
1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_to_cart!
|
58
|
+
cart_response = build_cart_request
|
59
|
+
update!(
|
60
|
+
external_id: cart_response.id,
|
61
|
+
price: cart_response.price,
|
62
|
+
status: cart_response.status
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def pay!
|
67
|
+
raise "Cannot pay label in #{status} status" unless can_pay?
|
68
|
+
|
69
|
+
payment_response = me_client.pay_label(external_id)
|
70
|
+
update!(
|
71
|
+
status: payment_response.purchase.status,
|
72
|
+
paid_at: payment_response.purchase.paid_at
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def generate!
|
77
|
+
raise "Cannot generate label in #{status} status" unless can_generate?
|
78
|
+
|
79
|
+
me_client.generate_label(external_id)
|
80
|
+
update!(status: 'generated_label')
|
81
|
+
touch(:generated_at)
|
82
|
+
end
|
83
|
+
|
84
|
+
def print!
|
85
|
+
raise "Cannot print label in #{status} status" unless can_print?
|
86
|
+
|
87
|
+
print_response = me_client.print_label(external_id)
|
88
|
+
get_response = me_client.get_label(external_id)
|
89
|
+
|
90
|
+
update!(
|
91
|
+
status: 'completed_label',
|
92
|
+
link: print_response.first,
|
93
|
+
tracking_code: get_response.self_tracking
|
94
|
+
)
|
95
|
+
touch(:completed_at)
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def me_client
|
101
|
+
@me_client ||= MeClient.for_account(account)
|
102
|
+
end
|
103
|
+
|
104
|
+
def build_cart_request
|
105
|
+
order = Spree::Order.find(spree_order_id)
|
106
|
+
address = order.ship_address
|
107
|
+
package = Spree::Stock::SimpleCoordinator.new(order).send(:build_packages).sole
|
108
|
+
shipping_method = order.shipments.sole.selected_shipping_rate.shipping_method
|
109
|
+
service_data = MelhorEnvio::SHIPPING_METHODS.find { |m| m[:name] == shipping_method.name }
|
110
|
+
dimensions = PackageEstimator.new(package).estimate_dimensions
|
111
|
+
|
112
|
+
me_client.add_label_to_cart(
|
113
|
+
service_id: service_data[:external_id],
|
114
|
+
from_name: account.name,
|
115
|
+
from_phone: account.phone,
|
116
|
+
from_email: account.email,
|
117
|
+
from_address: account.address,
|
118
|
+
from_address_complement: account.address_complement,
|
119
|
+
from_address_number: account.address_number,
|
120
|
+
from_address_district: account.address_district,
|
121
|
+
from_address_city: account.address_city,
|
122
|
+
from_postal_code: account.postal_code_from,
|
123
|
+
from_address_state_abbr: account.address_state_abbr,
|
124
|
+
from_tax_id: account.tax_id,
|
125
|
+
to_name: address.name,
|
126
|
+
to_phone: address.phone,
|
127
|
+
to_email: order.email,
|
128
|
+
to_address: address.address1,
|
129
|
+
to_address_complement: address.address2,
|
130
|
+
to_address_number: address.number,
|
131
|
+
to_address_district: address.district,
|
132
|
+
to_address_city: address.city,
|
133
|
+
to_postal_code: address.zipcode,
|
134
|
+
to_address_state_abbr: address.state.abbr,
|
135
|
+
to_tax_id: order.tax_id,
|
136
|
+
volumes: [
|
137
|
+
MeApi::Volume.new(
|
138
|
+
width_cm: dimensions[0],
|
139
|
+
height_cm: dimensions[1],
|
140
|
+
length_cm: dimensions[2],
|
141
|
+
weight_kg: package.weight / 1000
|
142
|
+
)
|
143
|
+
],
|
144
|
+
products: order.line_items.map do |line_item|
|
145
|
+
MeApi::Product.new(
|
146
|
+
name: line_item.name,
|
147
|
+
quantity: line_item.quantity,
|
148
|
+
unitary_value: line_item.price
|
149
|
+
)
|
150
|
+
end,
|
151
|
+
insurance_value: order.total
|
152
|
+
)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|