Skip to content

Commit

Permalink
Merge pull request #400 from Purple-Stock/staging
Browse files Browse the repository at this point in the history
update the stock by qr code
  • Loading branch information
puppe1990 authored Oct 31, 2024
2 parents 6fc405b + f5576d6 commit a27e234
Show file tree
Hide file tree
Showing 6 changed files with 365 additions and 10 deletions.
35 changes: 35 additions & 0 deletions app/controllers/api/v1/bling_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module Api
module V1
class BlingController < ApplicationController
def update_stock
warehouse_id = params[:warehouse_id].presence ||
Warehouse.find_by(account_id: current_tenant, is_default: true)&.bling_id ||
Warehouse.first&.bling_id

result = Services::Bling::CreateStockRecord.call(
warehouse_id: warehouse_id,
product_id: params[:product_id],
quantity: params[:quantity],
operation: params[:operation],
notes: params[:notes],
tenant: current_tenant
)

if result.success?
render json: { success: true, data: result.data }
else
render json: { success: false, error: result.error }, status: :unprocessable_entity
end
end

private

def warehouse_not_found
render json: {
success: false,
error: "No warehouse found for this account"
}, status: :unprocessable_entity
end
end
end
end
42 changes: 34 additions & 8 deletions app/controllers/products_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,20 +165,46 @@ def scan_qr_code
def update_stock_from_qr
@product = Product.find(params[:id])
quantity = params[:quantity].to_i
operation = params[:operation]

begin
ActiveRecord::Base.transaction do
# Create a new stock record or update existing
if @product.stock.nil?
@product.create_stock(quantity: quantity)
else
@product.stock.update!(quantity: quantity)
# Only update stock in Bling if bling_id is present
if @product.bling_id.present?
result = Services::Bling::CreateStockRecord.call(
warehouse_id: params[:warehouse_id],
product_id: @product.bling_id,
quantity: quantity,
operation: operation,
tenant: current_tenant,
notes: params[:notes]
)

unless result.success?
error_message = if result.error.include?('TOO_MANY_REQUESTS')
'Rate limit exceeded. Please wait a few seconds and try again.'
else
"Bling API Error: #{result.error}"
end
raise StandardError, error_message
end

render json: { success: true, message: 'Stock updated successfully' }
render json: {
success: true,
message: 'Stock updated successfully in Bling',
bling_sync: true
}
else
render json: {
success: false,
error: 'Product does not have a Bling ID'
}, status: :unprocessable_entity
end
rescue StandardError => e
render json: { success: false, error: e.message }, status: :unprocessable_entity
render json: {
success: false,
error: e.message,
retry_allowed: e.message.include?('Rate limit exceeded')
}, status: :unprocessable_entity
end
end

Expand Down
110 changes: 110 additions & 0 deletions app/models/services/bling/create_stock_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# frozen_string_literal: true

require 'net/http'
require 'uri'
require 'json'

module Services
module Bling
class CreateStockRecord < ApplicationService
VALID_OPERATIONS = {
'B' => 'balanço',
'E' => 'entrada',
'S' => 'saída'
}.freeze

attr_reader :warehouse_id, :product_id, :quantity, :operation, :price, :cost, :notes, :tenant

def initialize(warehouse_id:, product_id:, quantity:, operation:, tenant:, price: nil, cost: nil, notes: nil)
@warehouse_id = warehouse_id
@product_id = product_id
@quantity = quantity
@operation = operation.to_s.upcase
@price = price
@cost = cost
@notes = notes
@tenant = tenant
end

def call
return missing_warehouse_error if warehouse_id.nil?
return invalid_operation_error unless valid_operation?

url = URI("https://www.bling.com.br/Api/v3/estoques")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Accept"] = "application/json"
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer #{bling_token}"
print('payload_tetas')
print(build_payload.to_json)
request.body = build_payload.to_json

response = http.request(request)
handle_response(response)
rescue StandardError => e
Rails.logger.error "Bling API Error: #{e.message}"
OpenStruct.new(success?: false, error: e.message)
end

private

def valid_operation?
VALID_OPERATIONS.key?(@operation)
end

def invalid_operation_error
OpenStruct.new(
success?: false,
error: "Invalid operation. Accepted values: B (#{VALID_OPERATIONS['B']}), " \
"E (#{VALID_OPERATIONS['E']}), S (#{VALID_OPERATIONS['S']})"
)
end

def missing_warehouse_error
OpenStruct.new(
success?: false,
error: "No warehouse found. Please set up a warehouse first."
)
end

def build_payload
{
deposito: {
id: warehouse_id
},
operacao: operation,
produto: {
id: product_id
},
quantidade: quantity.to_f,
preco: price&.to_f,
custo: cost&.to_f,
observacoes: notes
}.compact
end

def bling_token
@bling_token ||= BlingDatum.find_by(account_id: tenant).access_token
end

def handle_response(response)
case response.code.to_i
when 201, 200
OpenStruct.new(
success?: true,
data: JSON.parse(response.body)
)
else
OpenStruct.new(
success?: false,
error: "API Error: #{response.code} - #{response.body}"
)
end
end
end
end
end
3 changes: 2 additions & 1 deletion app/models/services/product/generate_qr_code.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def call(for_download: false)
object = {
id: @product.id,
account_id: @product.account_id,
sku: @product.decorate.sku
sku: @product.decorate.sku,
bling_id: @product.bling_id
}

qr_code = RQRCode::QRCode.new(object.to_json)
Expand Down
Loading

0 comments on commit a27e234

Please sign in to comment.