diff --git a/app/controllers/cart_payments_controller.rb b/app/controllers/cart_payments_controller.rb index 83724ac..4358d20 100644 --- a/app/controllers/cart_payments_controller.rb +++ b/app/controllers/cart_payments_controller.rb @@ -12,7 +12,7 @@ class CartPaymentsController < ApplicationController param :path, :cart_id, :integer, :required, 'Cart ID' param :body, :cart, :versionCart, :required, 'Cart' response :ok, 'Success', :readTransaction - response :not_found, 'No cart with that ID' + response :not_found, 'No cart with that ID or it is expired' response :conflict, 'The user\'s balance is too low' response :precondition_required, 'The cart is stale' response :gone, 'The cart payment is already being processed' diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 8f1cacb..e4a8c1b 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -48,6 +48,9 @@ class CartsController < ApplicationController property :id, :integer, :optional, 'Cart ID' property :user_id, :integer, :optional, 'User ID' property :total_price, :integer, :optional, 'Total Cart price' + property :expires_at, :date_time, :optional, + 'Date and time at which the cart expires, making it read-only, '\ + 'not payable for, and releasing product reservations' property :lock_version, :integer, :optional, 'Cart version' property :cart_items, :array, :optional, 'Cart Items', 'items' => {'$ref' => 'readCartItem'} @@ -103,6 +106,7 @@ def update if cart.save render json: cart, status: :ok, location: cart else + cart.reload render json: cart, status: :conflict, location: cart end end diff --git a/app/interactors/resolve_cart_and_user.rb b/app/interactors/resolve_cart_and_user.rb index 2db1651..3c77505 100644 --- a/app/interactors/resolve_cart_and_user.rb +++ b/app/interactors/resolve_cart_and_user.rb @@ -3,7 +3,7 @@ class ResolveCartAndUser def call begin - context.cart = Cart.find_by_id!(context.cart_id) + context.cart = Cart.unexpired.find_by_id!(context.cart_id) rescue ActiveRecord::RecordNotFound context.fail!(message: 'generic.not_found') end diff --git a/app/models/cart.rb b/app/models/cart.rb index 696d333..fb62f15 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -1,8 +1,34 @@ class Cart < ActiveRecord::Base + EXPIRE_AFTER = 300 # seconds + belongs_to :user has_many :cart_items, dependent: :destroy, autosave: true + validate :ensure_unexpired + + scope :unexpired, -> { where unexpired_condition } + + def self.unexpired_condition + arel_table[:updated_at].gteq(EXPIRE_AFTER.seconds.ago) + end + def total_price cart_items.map(&:total_price).reduce(:+) end + + def expires_at + (updated_at || DateTime.now) + EXPIRE_AFTER.seconds + end + + def expired? + DateTime.now > expires_at + end + + private + + def ensure_unexpired + if expired? + errors.add :expires_at, "can't be in the past" + end + end end diff --git a/app/models/cart_item.rb b/app/models/cart_item.rb index f276047..8538bec 100644 --- a/app/models/cart_item.rb +++ b/app/models/cart_item.rb @@ -5,6 +5,8 @@ class CartItem < ActiveRecord::Base validate :enough_items_present_in_pricing + scope :unexpired, -> { joins(:cart).where(Cart.unexpired_condition) } + def product_name product.try(:name) || '' end diff --git a/app/models/pricing.rb b/app/models/pricing.rb index 850054d..af98e77 100644 --- a/app/models/pricing.rb +++ b/app/models/pricing.rb @@ -6,6 +6,6 @@ class Pricing < ActiveRecord::Base validates :price, numericality: { only_integer: true } def available_quantity - quantity - cart_items.sum(:quantity) + quantity - cart_items.unexpired.sum(:quantity) end end diff --git a/app/representers/cart_representer.rb b/app/representers/cart_representer.rb index 17c0d25..c784f6a 100644 --- a/app/representers/cart_representer.rb +++ b/app/representers/cart_representer.rb @@ -4,6 +4,7 @@ class CartRepresenter < ApplicationDecorator property :lock_version, type: Integer property :user_id, type: Integer property :total_price, writeable: false, type: Integer + property :expires_at, writeable: false, type: Date collection( :cart_items,