Skip to content

Commit f5576d6

Browse files
committed
update the stock by qr code
1 parent cb2628a commit f5576d6

File tree

6 files changed

+365
-10
lines changed

6 files changed

+365
-10
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module Api
2+
module V1
3+
class BlingController < ApplicationController
4+
def update_stock
5+
warehouse_id = params[:warehouse_id].presence ||
6+
Warehouse.find_by(account_id: current_tenant, is_default: true)&.bling_id ||
7+
Warehouse.first&.bling_id
8+
9+
result = Services::Bling::CreateStockRecord.call(
10+
warehouse_id: warehouse_id,
11+
product_id: params[:product_id],
12+
quantity: params[:quantity],
13+
operation: params[:operation],
14+
notes: params[:notes],
15+
tenant: current_tenant
16+
)
17+
18+
if result.success?
19+
render json: { success: true, data: result.data }
20+
else
21+
render json: { success: false, error: result.error }, status: :unprocessable_entity
22+
end
23+
end
24+
25+
private
26+
27+
def warehouse_not_found
28+
render json: {
29+
success: false,
30+
error: "No warehouse found for this account"
31+
}, status: :unprocessable_entity
32+
end
33+
end
34+
end
35+
end

app/controllers/products_controller.rb

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,20 +165,46 @@ def scan_qr_code
165165
def update_stock_from_qr
166166
@product = Product.find(params[:id])
167167
quantity = params[:quantity].to_i
168+
operation = params[:operation]
168169

169170
begin
170-
ActiveRecord::Base.transaction do
171-
# Create a new stock record or update existing
172-
if @product.stock.nil?
173-
@product.create_stock(quantity: quantity)
174-
else
175-
@product.stock.update!(quantity: quantity)
171+
# Only update stock in Bling if bling_id is present
172+
if @product.bling_id.present?
173+
result = Services::Bling::CreateStockRecord.call(
174+
warehouse_id: params[:warehouse_id],
175+
product_id: @product.bling_id,
176+
quantity: quantity,
177+
operation: operation,
178+
tenant: current_tenant,
179+
notes: params[:notes]
180+
)
181+
182+
unless result.success?
183+
error_message = if result.error.include?('TOO_MANY_REQUESTS')
184+
'Rate limit exceeded. Please wait a few seconds and try again.'
185+
else
186+
"Bling API Error: #{result.error}"
187+
end
188+
raise StandardError, error_message
176189
end
177190

178-
render json: { success: true, message: 'Stock updated successfully' }
191+
render json: {
192+
success: true,
193+
message: 'Stock updated successfully in Bling',
194+
bling_sync: true
195+
}
196+
else
197+
render json: {
198+
success: false,
199+
error: 'Product does not have a Bling ID'
200+
}, status: :unprocessable_entity
179201
end
180202
rescue StandardError => e
181-
render json: { success: false, error: e.message }, status: :unprocessable_entity
203+
render json: {
204+
success: false,
205+
error: e.message,
206+
retry_allowed: e.message.include?('Rate limit exceeded')
207+
}, status: :unprocessable_entity
182208
end
183209
end
184210

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# frozen_string_literal: true
2+
3+
require 'net/http'
4+
require 'uri'
5+
require 'json'
6+
7+
module Services
8+
module Bling
9+
class CreateStockRecord < ApplicationService
10+
VALID_OPERATIONS = {
11+
'B' => 'balanço',
12+
'E' => 'entrada',
13+
'S' => 'saída'
14+
}.freeze
15+
16+
attr_reader :warehouse_id, :product_id, :quantity, :operation, :price, :cost, :notes, :tenant
17+
18+
def initialize(warehouse_id:, product_id:, quantity:, operation:, tenant:, price: nil, cost: nil, notes: nil)
19+
@warehouse_id = warehouse_id
20+
@product_id = product_id
21+
@quantity = quantity
22+
@operation = operation.to_s.upcase
23+
@price = price
24+
@cost = cost
25+
@notes = notes
26+
@tenant = tenant
27+
end
28+
29+
def call
30+
return missing_warehouse_error if warehouse_id.nil?
31+
return invalid_operation_error unless valid_operation?
32+
33+
url = URI("https://www.bling.com.br/Api/v3/estoques")
34+
35+
http = Net::HTTP.new(url.host, url.port)
36+
http.use_ssl = true
37+
38+
request = Net::HTTP::Post.new(url)
39+
request["Accept"] = "application/json"
40+
request["Content-Type"] = "application/json"
41+
request["Authorization"] = "Bearer #{bling_token}"
42+
print('payload_tetas')
43+
print(build_payload.to_json)
44+
request.body = build_payload.to_json
45+
46+
response = http.request(request)
47+
handle_response(response)
48+
rescue StandardError => e
49+
Rails.logger.error "Bling API Error: #{e.message}"
50+
OpenStruct.new(success?: false, error: e.message)
51+
end
52+
53+
private
54+
55+
def valid_operation?
56+
VALID_OPERATIONS.key?(@operation)
57+
end
58+
59+
def invalid_operation_error
60+
OpenStruct.new(
61+
success?: false,
62+
error: "Invalid operation. Accepted values: B (#{VALID_OPERATIONS['B']}), " \
63+
"E (#{VALID_OPERATIONS['E']}), S (#{VALID_OPERATIONS['S']})"
64+
)
65+
end
66+
67+
def missing_warehouse_error
68+
OpenStruct.new(
69+
success?: false,
70+
error: "No warehouse found. Please set up a warehouse first."
71+
)
72+
end
73+
74+
def build_payload
75+
{
76+
deposito: {
77+
id: warehouse_id
78+
},
79+
operacao: operation,
80+
produto: {
81+
id: product_id
82+
},
83+
quantidade: quantity.to_f,
84+
preco: price&.to_f,
85+
custo: cost&.to_f,
86+
observacoes: notes
87+
}.compact
88+
end
89+
90+
def bling_token
91+
@bling_token ||= BlingDatum.find_by(account_id: tenant).access_token
92+
end
93+
94+
def handle_response(response)
95+
case response.code.to_i
96+
when 201, 200
97+
OpenStruct.new(
98+
success?: true,
99+
data: JSON.parse(response.body)
100+
)
101+
else
102+
OpenStruct.new(
103+
success?: false,
104+
error: "API Error: #{response.code} - #{response.body}"
105+
)
106+
end
107+
end
108+
end
109+
end
110+
end

app/models/services/product/generate_qr_code.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ def call(for_download: false)
1818
object = {
1919
id: @product.id,
2020
account_id: @product.account_id,
21-
sku: @product.decorate.sku
21+
sku: @product.decorate.sku,
22+
bling_id: @product.bling_id
2223
}
2324

2425
qr_code = RQRCode::QRCode.new(object.to_json)

0 commit comments

Comments
 (0)