diff --git a/app/models/order_item.rb b/app/models/order_item.rb index ee32c6c..c7346d8 100644 --- a/app/models/order_item.rb +++ b/app/models/order_item.rb @@ -8,7 +8,11 @@ class OrderItem < ApplicationRecord # una modificación que tenga que devolverle unidades no sabe a dónde. belongs_to :warehouse, optional: true - validates :quantity, numericality: { greater_than: 0 } + # Entero: la columna es integer y guardaba `0.5` como 0 y `2.7` como 2. El + # primero pasaba la validación (0,5 > 0) y reventaba después en DeductStock + # con un 500; el segundo se truncaba sin aviso. Se valida antes de escribir, + # así el alta y el webhook responden 422 con el motivo. + validates :quantity, numericality: { only_integer: true, greater_than: 0 } validates :unit_price, numericality: { greater_than_or_equal_to: 0 } validate :product_belongs_to_same_company_as_order validate :warehouse_belongs_to_same_company_as_order diff --git a/spec/models/order_item_spec.rb b/spec/models/order_item_spec.rb index d38b3ab..aa02c12 100644 --- a/spec/models/order_item_spec.rb +++ b/spec/models/order_item_spec.rb @@ -40,6 +40,19 @@ expect(order_item).not_to be_valid end + # La columna es integer: 0,5 se guardaba como 0 y 2,7 como 2. + it 'refuses a fractional quantity', :aggregate_failures do + [0.5, 2.7, '1.5'].each do |quantity| + order_item.quantity = quantity + expect(order_item).not_to be_valid, "#{quantity.inspect} should be refused" + end + end + + it 'accepts an integer that comes as text from a form' do + order_item.quantity = '3' + expect(order_item).to be_valid + end + it 'validates unit_price is not negative' do order_item.unit_price = -1 expect(order_item).not_to be_valid diff --git a/spec/requests/api/v1/orders_spec.rb b/spec/requests/api/v1/orders_spec.rb index 63f3ddb..3cafee1 100644 --- a/spec/requests/api/v1/orders_spec.rb +++ b/spec/requests/api/v1/orders_spec.rb @@ -396,6 +396,21 @@ def order_of_another_company expect(response).to have_http_status(:unprocessable_content) end + # Pasaba la validación (0,5 > 0), la columna integer la guardaba en 0 y + # DeductStock reventaba con ArgumentError: 500. + it 'rejects a quantity below one unit with 422, not 500', :aggregate_failures do + post_order(build_payload(items: [default_item.merge(quantity: 0.5)])) + + expect(response).to have_http_status(:unprocessable_content) + expect(response.parsed_body['error']).to include('must be an integer') + end + + it 'rejects a fractional quantity instead of truncating it', :aggregate_failures do + expect { post_order(build_payload(items: [default_item.merge(quantity: 2.7)])) } + .not_to change(Order, :count) + expect(response).to have_http_status(:unprocessable_content) + end + it 'rejects when warehouse belongs to another company' do other_wh = other_company_warehouse post_order(build_payload(items: [default_item.merge(warehouse_id: other_wh.id)]))