sales_controller.rb 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. class SalesController < ApplicationController
  2. ##--- Abilities
  3. load_and_authorize_resource
  4. ##--- Breadcrum_rails
  5. add_breadcrumb I18n.t("breadcrumbs." + controller_name), :sales_path
  6. add_breadcrumb "Nueva " + I18n.t("breadcrumbs." + controller_name).singularize, :new_sale_path, only: :new
  7. add_breadcrumb "Detalle de la " + I18n.t("breadcrumbs." + controller_name).singularize, :sale_path, only: :show
  8. add_breadcrumb "Editar " + I18n.t("breadcrumbs." + controller_name).singularize, :edit_sale_path, only: :edit
  9. before_action :set_sale, only: [:show, :edit, :update, :destroy]
  10. before_action :get_filters, only: [:index, :show, :edit, :new, :sales_reserved]
  11. # GET /sales
  12. # GET /sales.json
  13. def index
  14. today = Date.current
  15. thirty_day_ago = today - 30
  16. @sales = current_user.usertype == "A" || current_user.usertype == "SS" ? Sale.includes(:customer, :user, :seller, :sales_details).where(date_sale: thirty_day_ago..today).where.not(saletype: 2).order(" created_at DESC ") : Pointsale.find(current_user.pointsale_id).sales.includes(:customer, :user, :seller).where(date_sale: thirty_day_ago..today).where.not(saletype: 2).order("created_at DESC")
  17. end
  18. def sales_reserved
  19. beg_of_month = Date.current.beginning_of_month
  20. end_of_month = Date.current.end_of_month
  21. @has_open_cash_register = if current_user.usertype == 'C'
  22. session[:open_cash_register_id].present?
  23. elsif current_user.usertype == 'G'
  24. current_user.pointsale.get_open_cash_register.present?
  25. elsif current_user.usertype == 'A'
  26. false
  27. end
  28. @sales = current_user.usertype == "A" || current_user.usertype == "SS" ? Sale.where(saletype: 2).order(" created_at DESC ") : Pointsale.find(current_user.pointsale_id).sales.where(saletype: 2).order(" created_at DESC")
  29. end
  30. # GET /sales/1
  31. # GET /sales/1.json
  32. def show
  33. @payments = CashRegistersMove.where(sale_id: @sale.id, status: 1)
  34. # saca la devolucion si es que hay.
  35. @products_return = ProductsReturn.find_by(sale_id: @sale.id)
  36. @returned_prods_ids = Array.new
  37. @returned_prods_ids = @products_return.products_return_ins.pluck(:product_id) if @products_return.present?
  38. end
  39. # GET /sales/new
  40. def new
  41. @sale = Sale.new
  42. @sale.sales_details.new
  43. @general_public_id = Customer.find_by(is_public: 1).id
  44. @pre_sales = PreSale.where(user_id: current_user.id)
  45. @sale.saletype = 'cash'
  46. # se desactivan cuando tienen pre sales, para mantener la congruencia de los datos.
  47. @disabled_select = false
  48. @disabled_button = true
  49. @enable_radios = true
  50. pointsale = Pointsale.find(current_user.pointsale_id)
  51. @opened_cash_registers = pointsale.open_cash_registers.abiertas
  52. @sale.open_cash_register_id = session[:open_cash_register_id] || nil
  53. @seller = @sale.seller_id.present? ? @sale.seller_id : (pointsale.sales.present? ? pointsale.sales.activas.last.seller_id : nil)
  54. if @pre_sales.present?
  55. @sale.saletype = @pre_sales[0].sale_type
  56. @sale.customer_id = @pre_sales[0].customer_id
  57. @sale.open_cash_register_id = @pre_sales[0].open_cash_register_id
  58. @disabled_select = true
  59. @disabled_button = false
  60. @enable_radios = false
  61. end
  62. end
  63. # GET /sales/1/edit
  64. def edit; end
  65. # POST /sales
  66. # POST /sales.json
  67. # rubocop:disable Metrics/BlockLength
  68. def create
  69. @sale = Sale.new(sale_params)
  70. @pre_sales = PreSale.where(user_id: current_user.id)
  71. @sale.user_id = current_user.id
  72. # @sale.open_cash_register_id = session[:open_cash_register_id]
  73. @sale.status = :notpaid
  74. @sale.expiration_date = Date.today + @pos_config.days_cancel_reserved if @sale.reserved?
  75. respond_to do |format|
  76. if @sale.save
  77. @sale.audit_comment = "Venta #{@sale.sale_code} por #{@sale.total} creada."
  78. # agregar detalles de la venta
  79. @pre_sales.each do |pre_sale|
  80. detail = SalesDetail.new(product_id: pre_sale.product_id, unit_price: pre_sale.unit_price, quantity: pre_sale.quantity, amount: pre_sale.amount, tax: pre_sale.tax, discount: pre_sale.discount, total: pre_sale.total, special_price_id: pre_sale.special_price_id, status: :active, haggle: pre_sale.haggle, haggle_percent: pre_sale.haggle_percent)
  81. @sale.sales_details << detail
  82. pre_sale.destroy
  83. # actualizar stock del producto
  84. stock_product = AvailableProduct.find_by(product_id: detail.product_id, pointsale_id: @sale.get_pointsale.id)
  85. next if stock_product.blank?
  86. if stock_product.stock.present?
  87. stock_product.stock -= detail.quantity
  88. stock_product.save
  89. else
  90. errors.add(:base, "No se tiene registrado el stock de alguno de los productos. Es necesario configurarlo antes de generar una venta")
  91. format.json { render json: @sale.errors.values, status: :unprocessable_entity }
  92. end
  93. # guardar en bitacora de inventario
  94. move = InventoriesMove.new(product_id: detail.product_id, sale_id: @sale.id, quantity: detail.quantity, move_type: "outgoing", reason: "sale")
  95. move.save
  96. end
  97. # dependiendo el tipo de venta: contado/credito determina que hacer
  98. if @sale.cash?
  99. format.js { redirect_to new_cash_registers_move_path(sale: @sale.id) }
  100. elsif @sale.credit?
  101. credit = Credit.new(customer_id: @sale.customer_id, pointsale_id: current_user.pointsale_id, sale_id: @sale.id, total: @sale.total, rest: @sale.total, status: "active", credit_note: @sale.credit_note.present? ? @sale.credit_note : "")
  102. credit.save
  103. flash[:success] = "Venta a crédito registrada al cliente: #{@sale.customer.nick_name} por $ #{@sale.total}"
  104. format.js { render 'create_credit_sale' }
  105. elsif @sale.reserved?
  106. format.js { redirect_to new_cash_registers_move_path(sale: @sale.id) }
  107. end
  108. else
  109. format.js
  110. format.json { render json: @sale.errors, status: :unprocessable_entity }
  111. end
  112. end
  113. end
  114. # rubocop:enable Metrics/BlockLength
  115. # PATCH/PUT /sales/1
  116. # PATCH/PUT /sales/1.json
  117. def update
  118. respond_to do |format|
  119. if @sale.update(sale_params)
  120. format.html { redirect_to @sale, notice: 'Venta modificada.' }
  121. format.json { render :show, status: :ok, location: @sale }
  122. else
  123. format.html { render :edit }
  124. format.json { render json: @sale.errors, status: :unprocessable_entity }
  125. end
  126. end
  127. end
  128. # DELETE /sales/1
  129. # DELETE /sales/1.json
  130. # rubocop:disable Metrics/BlockLength
  131. def destroy
  132. respond_to do |format|
  133. @sale.audit_comment = "Venta #{@sale.sale_code} cancelada."
  134. if @sale.update_attributes(status: :cancelled)
  135. # rubocop:disable Metrics/BlockNesting
  136. if @sale.reserved?
  137. return_cash = params[:return_cash]
  138. if return_cash == 'true'
  139. moves = CashRegistersMove.where(sale_id: @sale.id, move_type: 1)
  140. if moves.present?
  141. if moves[0].open_cash_register.closed?
  142. quantity_to_return = moves.sum(:quantity)
  143. new_cash_move = CashRegistersMove.new(open_cash_register_id: session[:open_cash_register_id], payment_method_id: PaymentMethod.find_by(isCash: 1).id, quantity: quantity_to_return, move_type: :egreso, sale_id: @sale.id, concept: :sale, status: :active)
  144. new_cash_move.skip_received_validation = true
  145. new_cash_move.save
  146. else
  147. moves.destroy_all
  148. end
  149. end
  150. end
  151. elsif @sale.cash?
  152. # checa si hay pagos de esta venta
  153. moves = CashRegistersMove.where(sale_id: @sale.id)
  154. # si la caja sigue abierta, solo elimina los moves, si ya corto, genera un egreso por esa cantidad
  155. if moves.present?
  156. if moves[0].open_cash_register.closed?
  157. new_cash_move = CashRegistersMove.new(open_cash_register_id: session[:open_cash_register_id], payment_method_id: PaymentMethod.find_by(isCash: true).id, quantity: moves.sum(:quantity), move_type: :egreso, sale_id: moves[0].sale_id, concept: :sale, ticket: moves[0].sale.sale_code, status: :active)
  158. new_cash_move.skip_received_validation = true
  159. new_cash_move.save
  160. else
  161. moves.destroy_all
  162. end
  163. end
  164. elsif @sale.credit?
  165. credit = Credit.find_by(sale_id: @sale.id, customer_id: @sale.customer_id)
  166. credit.update_attributes(status: :cancelled)
  167. end
  168. # rubocop:enable Metrics/BlockNesting
  169. @sale.sales_details.each do |detail|
  170. detail.update_attributes(status: :inactive)
  171. stock_product = AvailableProduct.find_by(product_id: detail.product_id, pointsale_id: @sale.get_pointsale.id)
  172. next if stock_product.blank?
  173. # sumarle al stock del producto
  174. stock = stock_product.stock + detail.quantity
  175. stock_product.update_attributes(stock: stock)
  176. # guardar en bitacora de inventario
  177. move = InventoriesMove.new(product_id: detail.product_id, sale_id: @sale.id, quantity: detail.quantity, move_type: "incoming", reason: (@sale.reserved? ? "sale_reserved_cancelled" : "sale_cancel"))
  178. move.save
  179. end
  180. format.html { redirect_to (@sale.reserved? ? sales_reserved_path : sales_url), warning: (@sale.reserved? ? "Apartado con folio #{@sale.sale_code} cancelado." : "Venta con folio #{@sale.sale_code} cancelado.") }
  181. format.json { head :no_content }
  182. end
  183. end
  184. end
  185. # rubocop:enable Metrics/BlockLength
  186. def find_sales_by_date
  187. if params[:begin_date].present? && params[:end_date].present?
  188. start_date = DateTime.parse(params[:begin_date])
  189. end_date = DateTime.parse(params[:end_date])
  190. else
  191. start_date = Date.today.beginning_of_month
  192. end_date = Date.today.end_of_month
  193. end
  194. @sales = current_user.usertype == "A" || current_user.usertype == "SS" ? Sale.includes(:customer, :user, :seller, :sales_details).where(date_sale: start_date..end_date).where.not(saletype: 2).order(" created_at DESC ") : Pointsale.find(current_user.pointsale_id).sales.includes(:customer, :user, :seller, :sales_details).where(date_sale: start_date..end_date).where.not(saletype: 2).order(" created_at DESC ")
  195. respond_to do |format|
  196. format.js
  197. end
  198. end
  199. def find_customer_sales_by_date
  200. if params[:begin_date].present? && params[:end_date].present?
  201. start_date = DateTime.parse(params[:begin_date])
  202. end_date = DateTime.parse(params[:end_date])
  203. else
  204. start_date = Date.today.beginning_of_month
  205. end_date = Date.today.end_of_month
  206. end
  207. cliente = params[:cliente]
  208. @sales = Sale.where(date_sale: start_date..end_date, customer_id: cliente).where.not(saletype: 2).order(" id DESC ")
  209. respond_to do |format|
  210. format.js { render action: "find_sales_by_date" }
  211. end
  212. end
  213. def find_reserved_sales_by_date
  214. if params[:begin_date].present? && params[:end_date].present?
  215. start_date = DateTime.parse(params[:begin_date])
  216. end_date = DateTime.parse(params[:end_date])
  217. else
  218. start_date = Date.today.beginning_of_month
  219. end_date = Date.today.end_of_month
  220. end
  221. @sales = current_user.usertype == "A" || current_user.usertype == "SS" ? Sale.includes(:customer, :user, :seller, :sales_details).where(date_sale: start_date..end_date, saletype: 2).order(" created_at DESC ") : Pointsale.find(current_user.pointsale_id).sales.includes(:customer, :user, :seller, :sales_details).where(date_sale: start_date..end_date).where(saletype: 2).order(" created_at DESC ")
  222. respond_to do |format|
  223. format.js
  224. end
  225. end
  226. def return_expired
  227. @sale = Sale.find(params[:sale_id])
  228. respond_to do |format|
  229. if @sale.update_attributes(status: :cancelled_by_expiration)
  230. @sale.sales_details.each do |detail|
  231. detail.update_attributes(status: :inactive)
  232. stock_product = AvailableProduct.find_by(product_id: detail.product_id, pointsale_id: @sale.get_pointsale.id)
  233. next if stock_product.blank?
  234. # sumarle al stock del producto
  235. stock = stock_product.stock + detail.quantity
  236. stock_product.update_attributes(stock: stock)
  237. # guardar en bitacora de inventario
  238. move = InventoriesMove.new(product_id: detail.product_id, sale_id: @sale.id, quantity: detail.quantity, move_type: "incoming", reason: "sale_expired")
  239. move.save
  240. end
  241. format.html { redirect_to sales_reserved_url, warning: "Productos reingresados al inventario del apartado #{@sale.sale_code}." }
  242. format.json { head :no_content }
  243. end
  244. end
  245. end
  246. def liquidate_reserve
  247. respond_to do |format|
  248. @sale = Sale.find(params[:sale_id])
  249. @payments = CashRegistersMove.where(sale_id: @sale.id, status: 1)
  250. format.js { redirect_to new_cash_registers_move_path(sale: @sale.id) }
  251. end
  252. end
  253. def cancel_reserved_sale
  254. @sale = Sale.find(params[:sale_id])
  255. end
  256. def print_receipt
  257. respond_to do |format|
  258. sale = Sale.find(params[:sale_id])
  259. format.pdf do
  260. render pdf: "ticket_venta_#{sale.id}", template: "sales/receipt.pdf.erb", layout: 'receipt.html.erb', locals: { sale: sale }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm'
  261. end
  262. end
  263. end
  264. def print_reserve_receipt
  265. # ticket para apartado
  266. respond_to do |format|
  267. sale = Sale.find(params[:sale_id])
  268. # debt = sale.cash_registers_moves.first.quantity
  269. debt = sale.cash_registers_moves.sum(:quantity)
  270. format.pdf do
  271. render pdf: "ticket_apartado_#{sale.id}", template: "sales/receipt_reserve.pdf.erb", layout: 'receipt.html.erb', locals: { sale: sale, debt: debt }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm'
  272. end
  273. end
  274. end
  275. def print_credit_receipt
  276. # ticket para credito
  277. respond_to do |format|
  278. sale = Sale.find(params[:sale_id])
  279. debt = sale.customer.credits.activos.sum(:rest)
  280. format.pdf do
  281. render pdf: "ticket_credito_#{sale.id}", template: "sales/receipt_credit.pdf.erb", layout: 'receipt.html.erb', locals: { sale: sale, debt: debt }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm'
  282. end
  283. end
  284. end
  285. def print_partial_payment_receipt
  286. # ticket para abonos a apartado
  287. respond_to do |format|
  288. sale = Sale.find(params[:sale_id])
  289. new_moves = CashRegistersMove.where(id: params[:new_moves_array])
  290. quantity = new_moves.sum(:quantity)
  291. format.pdf do
  292. render pdf: "ticket_abono_apartado_#{sale.id}", template: "sales/receipt_partial_payment.pdf.erb", layout: 'receipt.html.erb', locals: { sale: sale, new_payments_quantity: quantity, moves: new_moves }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm'
  293. end
  294. end
  295. end
  296. def print_credit_payment_receipt
  297. # ticket para abonos a credito
  298. respond_to do |format|
  299. sale = Sale.find(params[:sale_id])
  300. deuda = params[:debts].to_f
  301. cash_move = CashRegistersMove.where(sale_id: sale.id).last
  302. quantity = cash_move.quantity
  303. debt = Credit.where(customer_id: sale.customer_id).sum(:rest)
  304. format.pdf do
  305. render pdf: "ticket_abono_credito_#{sale.id}", template: "sales/receipt_credit_payment.pdf.erb", layout: 'receipt.html.erb', locals: { sale: sale, new_payment: quantity, debt: debt, deuda: deuda, move: cash_move }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm'
  306. end
  307. end
  308. end
  309. def add_haggle
  310. @pre_sale = PreSale.find(params[:pre_sale])
  311. @haggle_percent = !current_user.pointsale.haggle_percent.blank? ? current_user.pointsale.haggle_percent : @pos_config.haggle_in_sale_percent
  312. @suggested_haggle = (@haggle_percent.to_f / 100) * @pre_sale.unit_price_w_discount
  313. end
  314. def create_haggle
  315. @pre_sale = PreSale.find(params[:pre_sale])
  316. @haggle_percent = params[:haggle_percent].present? ? params[:haggle_percent].to_f : nil
  317. @haggle_quantity = params[:haggle_quantity].present? ? params[:haggle_quantity].to_f : nil
  318. if @haggle_percent.present?
  319. @pre_sale.haggle_percent = @haggle_percent
  320. elsif @haggle_quantity.present?
  321. @pre_sale.haggle = @haggle_quantity
  322. end
  323. @pre_sale.get_totals
  324. respond_to do |format|
  325. if @pre_sale.save
  326. format.js
  327. end
  328. end
  329. end
  330. def find_sales_by_dates_or_code
  331. respond_to do |format|
  332. if params[:sale_code].present?
  333. @sales = Pointsale.find(current_user.pointsale_id).sales.activas.where(sale_code: params[:sale_code], saletype: 1).order("id DESC")
  334. else
  335. start_date = DateTime.parse(params[:start_date])
  336. end_date = DateTime.parse(params[:end_date])
  337. product_id = params[:product_id]
  338. @sales = product_id.present? ? Pointsale.find(current_user.pointsale_id).sales.activas.where(date_sale: start_date..end_date, saletype: 1).joins(:sales_details).where('sales_details.product_id = (?)', product_id).order("id DESC") : Pointsale.find(current_user.pointsale_id).sales.activas.where(date_sale: start_date..end_date, saletype: 1).joins(:sales_details).order("id DESC")
  339. end
  340. format.js
  341. end
  342. end
  343. def sales_per_month_report
  344. @pointsales = Pointsale.vigentes
  345. end
  346. def sales_per_month
  347. # start_date = DateTime.parse(params[:start_date])
  348. # end_date = DateTime.parse(params[:end_date])
  349. start_date = DateTime.parse(params[:start_date]).in_time_zone(Time.zone).beginning_of_day + 1.days
  350. end_date = DateTime.parse(params[:end_date]).in_time_zone(Time.zone).end_of_day + 1.days
  351. category = params[:category]
  352. subcategory = params[:subcategory]
  353. ids =
  354. if subcategory.present?
  355. subcategory
  356. elsif category.present?
  357. category = Category.find(category)
  358. [category.id, category.children.ids].flatten
  359. end
  360. @cash_sales_total = 0
  361. @reserved_sales_total = 0
  362. @credit_sales_total = 0
  363. if params[:pointsale_id].present?
  364. @pointsale = Pointsale.find(params[:pointsale_id])
  365. @incomes_in_period = @pointsale.cash_registers_moves.joins(:sale).where(move_type: '1', created_at: start_date..end_date)
  366. @sales = @pointsale.sales.joins(:products, products: :category).includes(:user, :seller).activas.where(created_at: start_date..end_date).order("id DESC")
  367. else
  368. @incomes_in_period = CashRegistersMove.joins(:sale).where(move_type: '1', created_at: start_date..end_date)
  369. @sales = Sale.joins(:products, products: :category).includes(:user, :seller).activas.where(created_at: start_date..end_date).order("id DESC")
  370. end
  371. if category.present?
  372. @sales = @sales.where(category: { id: ids })
  373. @incomes_in_period = @incomes_in_period.where(sale_id: @sales.ids)
  374. end
  375. @sales_quantity = @sales.size
  376. @prods_total = SalesDetail.where("sale_id IN (?)", @sales.pluck(:id)).sum(:quantity).round
  377. # @cash_sales_income = CashRegistersMove.activos.where("sale_id IN (?)", @sales.where(saletype: 1).pluck(:id)).where(created_at: start_date..end_date).sum(:quantity)
  378. # @reserved_sales_income = CashRegistersMove.activos.where("sale_id IN (?)", @sales.where(saletype: 2).pluck(:id)).where(created_at: start_date..end_date).sum(:quantity)
  379. # @credit_sales_income = CashRegistersMove.activos.where("sale_id IN (?)", @sales.where(saletype: 0).pluck(:id)).where(created_at: start_date..end_date).sum(:quantity)
  380. @cash_sales_income = @incomes_in_period.where('sales.saletype = ?', 1).sum(:quantity)
  381. @reserved_sales_income = @incomes_in_period.where('sales.saletype = ?', 2).sum(:quantity)
  382. @credit_sales_income = @incomes_in_period.where('sales.saletype = ?', 0).sum(:quantity)
  383. @sales_income = @incomes_in_period.sum(:quantity)
  384. @cash_sales_total = @sales.where(saletype: 1).sum(:total)
  385. @reserved_sales_total = @sales.where(saletype: 2).sum(:total)
  386. @credit_sales_total = @sales.where(saletype: 0).sum(:total)
  387. @sales_total = @sales.sum(:total)
  388. respond_to do |format|
  389. format.js
  390. end
  391. end
  392. private
  393. # Use callbacks to share common setup or constraints between actions.
  394. def set_sale
  395. @sale = Sale.find(params[:id])
  396. end
  397. def get_filters
  398. @current_page = params[:current_page].blank? ? 1 : params[:filter]
  399. @filter = params[:filter]
  400. end
  401. # Never trust parameters from the scary internet, only allow the white list through.
  402. def sale_params
  403. params.require(:sale).permit(:customer_id, :saletype, :amount, :tax, :discount, :total, :date_sale, :user_id, :seller_id, :sale_code, :credit_note, :open_cash_register_id)
  404. end
  405. end