products_controller.rb 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. class ProductsController < ApplicationController
  2. ##--- Abilities
  3. load_and_authorize_resource
  4. ##--- Breadcrum_rails
  5. add_breadcrumb I18n.t("breadcrumbs." + controller_name), :products_path, only: [:index, :new, :show, :edit]
  6. add_breadcrumb "Nuevo " + I18n.t("breadcrumbs." + controller_name).singularize, :new_product_path, only: :new
  7. add_breadcrumb "Detalle del " + I18n.t("breadcrumbs." + controller_name).singularize, :product_path, only: :show
  8. add_breadcrumb "Editar " + I18n.t("breadcrumbs." + controller_name).singularize, :edit_product_path, only: :edit
  9. add_breadcrumb "Seguimiento de productos", :product_track_path, only: :product_track
  10. before_action :set_product, only: [:show, :edit, :update, :destroy]
  11. before_action :set_product_id, only: [:list_prices, :list_prices_variants, :edit_variants, :update_variants, :edit_from_purchase, :update_from_purchase, :update_status]
  12. before_action :get_categories, only: [:create, :update]
  13. before_action :get_attrs, only: [:show, :edit, :update]
  14. before_action :get_filters, only: [:index, :show, :edit, :new]
  15. skip_before_action :get_categories, only: [:edit_from_purchase]
  16. # GET /products
  17. # GET /products.json
  18. def index
  19. respond_to do |format|
  20. format.html
  21. format.json { render json: ProductsDatatable.new(view_context, current_user) }
  22. end
  23. end
  24. def list_prices
  25. if @product.presentation
  26. # @available_products = @product.get_available_children(false)
  27. @pointsales = @product.get_available_children(true)
  28. end
  29. end
  30. def list_prices_variants
  31. children = Product.where("parent_id = ? and status != 0 ", params[:product_id]).pluck(:id)
  32. @variants = AvailableProduct.where("pointsale_id = ? and product_id IN (?)", params[:pointsale_id], children).includes(:product)
  33. @variants_json = Array.new
  34. @variants.each do |v|
  35. @variants_json.push(name: v.product.sku + " " + v.product.name + " <br><small>" + v.product.display_attributes + "</small>", price: v.product.get_price_sale(params[:pointsale_id]), available_product_id: v.id)
  36. end
  37. render json: @variants_json.to_json
  38. end
  39. def edit_variants; end
  40. def update_variants
  41. if @product.is_parent
  42. @product.update_attributes_to_variants(params[:new_size_list], params[:new_color_list], params[:new_style_list])
  43. @product.save_new_attributes(params[:mynewsizes], params[:mynewcolors], params[:mynewstyles])
  44. end
  45. respond_to do |format|
  46. if @product.save(validate: false)
  47. format.html { redirect_to products_url, success: 'Se modificaron las variantes del producto ' + @product.sku + ' - ' + @product.name + '.' }
  48. format.json { render :show, status: :ok, location: @product }
  49. else
  50. format.html { render :edit_variants }
  51. format.json { render json: @product.errors, status: :unprocessable_entity }
  52. end
  53. end
  54. end
  55. # GET /products/1
  56. # GET /products/1.json
  57. def show; end
  58. # GET /products/new
  59. def new
  60. @product = Product.new
  61. # Default unit is 'Pieza'
  62. @product.unit = Unit.where(unit: 'Pieza').first
  63. if params[:remoto].present?
  64. @remoto = params[:remoto]
  65. @pointsale = params[:pointsale]
  66. @warehouse = params[:warehouse]
  67. @supplier = params[:supplier]
  68. @exchange = params[:exchange]
  69. end
  70. @product.price_base = nil
  71. @product.price_sale = nil
  72. end
  73. # GET /products/1/edit
  74. def edit
  75. has_variants = @product.children.any?
  76. @with_presentation = has_variants ? true : false # si aun no tiene variantes, permitir clickear el switch
  77. end
  78. # POST /products
  79. # POST /products.json
  80. # rubocop:disable Metrics/BlockLength
  81. def create
  82. @product = Product.new(product_params)
  83. if @product.presentation
  84. @product.is_parent = true
  85. end
  86. message = 'El producto ' + @product.sku + ' fue creado.'
  87. @product.audit_comment = message
  88. respond_to do |format|
  89. if @product.save
  90. unless @product.is_parent?
  91. @product.generate_barcode
  92. @product.save
  93. end
  94. @product.save_variants(current_user)
  95. ##--- Para cuando se agrega un producto desde purchase
  96. if params[:remoto] == "true"
  97. ##--- Guardar pre_purchase
  98. @pre_purchases = Array.new
  99. if @product.presentation && @product.is_parent
  100. @product.children.each do |variant|
  101. save_pre_purchase(variant)
  102. set_available
  103. @pre_purchases << @pre_purchase
  104. end
  105. else
  106. save_pre_purchase(@product)
  107. set_available
  108. @pre_purchases << @pre_purchase
  109. end
  110. format.json { head :no_content }
  111. format.js
  112. else
  113. # crear available product para el p.v, cuando es sin variantes
  114. if current_user.usertype == 'G' && !@product.presentation && !@product.is_parent
  115. AvailableProduct.create(product_id: @product.id, pointsale_id: current_user.pointsale_id, stock: 0)
  116. end
  117. format.html { redirect_to products_url, success: message }
  118. format.json { render :show, status: :created, location: @product }
  119. end
  120. else
  121. format.html { render :new }
  122. format.json { render json: @product.errors, status: :unprocessable_entity }
  123. end
  124. end
  125. end
  126. # rubocop:enable Metrics/BlockLength
  127. # PATCH/PUT /products/1
  128. # PATCH/PUT /products/1.json
  129. def update
  130. respond_to do |format|
  131. @product.skip_sku_validation = true
  132. @product.is_parent = params[:product][:presentation] == 'true' ? true : false
  133. message = 'El producto ' + @product.sku + ' fue modificado.'
  134. @product.audit_comment = message
  135. if @product.update(product_params)
  136. if @product.is_parent
  137. @product.children.each_with_index do |variant, index|
  138. variant.skip_sku_validation = true
  139. params_to_edit = product_params
  140. params_to_edit[:sku] = @product.sku + (index + 1).to_s + "A"
  141. params_to_edit[:barcode] = variant.barcode
  142. variant.update_attributes(params_to_edit)
  143. end
  144. end
  145. format.html { redirect_to products_url, success: message }
  146. format.json { render :show, status: :ok, location: @product }
  147. else
  148. format.html { render :edit }
  149. format.json { render json: @product.errors, status: :unprocessable_entity }
  150. end
  151. end
  152. end
  153. def edit_from_purchase
  154. purchase_in_dollars = params[:is_in_dollars]
  155. exchange = params[:exchange].to_f
  156. if purchase_in_dollars == "true"
  157. @product.price_base_dollars = params[:product][:price_base].to_f
  158. price_in_peso = @product.price_base_dollars * exchange
  159. @product.price_base = @product.price_base.present? ? price_in_peso : nil
  160. @suggested_price_sale = (price_in_peso * (@pos_config.gain_margin / 100)) + price_in_peso
  161. else
  162. @product.price_base = params[:product][:price_base].to_f
  163. price_in_dollars = @product.price_base / exchange if exchange != 0
  164. @product.price_base_dollars = @product.price_base_dollars.present? ? price_in_dollars : nil
  165. @suggested_price_sale = (@product.price_base * (@pos_config.gain_margin / 100)) + @product.price_base
  166. end
  167. @suggested_price_sale = 0 if @suggested_price_sale.nil?
  168. respond_to do |format|
  169. @product.audit_comment = 'El producto ' + @product.sku + ' fue modificado.'
  170. @product.save
  171. format.json { head :no_content }
  172. format.js
  173. end
  174. end
  175. def update_from_purchase
  176. ##--- Si el producto es hijo, sacar el registro del padre para cambiar todos los valores
  177. unless @product.parent_id.nil?
  178. @product = Product.find(@product.parent_id)
  179. end
  180. @product.price_base = params[:product][:price_base].to_f
  181. @product.price_sale = params[:product][:price_sale].to_f
  182. message = "Se ha modificado el precio de venta base del producto " + @product.name
  183. respond_to do |format|
  184. if @product.save
  185. @product.children.each do |variant|
  186. variant.update_attributes(product_params)
  187. variant.save
  188. end
  189. @product.audit_comment = message
  190. format.json { head :no_content }
  191. format.js { flash[:success] = message }
  192. else
  193. @suggested_price_sale = params[:suggested_price_sale].to_f
  194. format.js { render :edit_from_purchase }
  195. format.json { render json: @available_product.errors, status: :unprocessable_entity }
  196. end
  197. end
  198. end
  199. def update_status
  200. product = @product
  201. if product.active?
  202. product.status = 2
  203. elsif product.inactive?
  204. product.status = 1
  205. end
  206. if product.presentation
  207. product.children.each do |pv|
  208. pv.status = product.status
  209. pv.save(validate: false)
  210. end
  211. end
  212. respond_to do |format|
  213. message = "El producto " + product.name + " fue " + (product.active? ? "activado" : "desactivado") + "."
  214. product.audit_comment = message
  215. if product.save(validate: false)
  216. format.html { redirect_to products_url, warning: message }
  217. # format.json { render :show, status: :ok, location: @pointsale }
  218. format.json { head :no_content }
  219. else
  220. format.html { redirect_to products_url }
  221. format.json { render json: @product.errors, status: :unprocessable_entity }
  222. end
  223. end
  224. end
  225. # DELETE /products/1
  226. # DELETE /products/1.json
  227. def destroy
  228. respond_to do |format|
  229. message = "El producto " + @product.name + " fue eliminado."
  230. @product.audit_comment = message
  231. if @product.update_attributes(status: 0)
  232. if @product.is_parent
  233. @product.children.each_with_index do |variant|
  234. variant.update_attributes(status: 0)
  235. variant.save
  236. end
  237. end
  238. format.html { redirect_to products_url, warning: message }
  239. format.json { head :no_content }
  240. else
  241. format.html { redirect_to products_url }
  242. format.json { render json: @product.errors, status: :unprocessable_entity }
  243. end
  244. end
  245. end
  246. def validate_unique_barcode
  247. respond_to do |format|
  248. @product = Product.find_by(barcode: params[:barcode])
  249. if @product.blank?
  250. format.js { head :ok }
  251. else
  252. format.js
  253. end
  254. end
  255. end
  256. def product_track
  257. #--Seguimiento de productos
  258. # @sales = SalesDetail.new
  259. product_id = params[:product_id]
  260. pointsale_id = params[:pointsale_id]
  261. start_date = DateTime.parse(params[:start_date]) if params[:start_date].present?
  262. end_date = DateTime.parse(params[:end_date]) if params[:end_date].present?
  263. if product_id.present?
  264. respond_to do |format|
  265. @sales = pointsale_id.present? ? Pointsale.find(pointsale_id).sales_details.includes(:sale).where('sales.status > 1 and sales_details.product_id = ? and sales.date_sale BETWEEN ? AND ?', product_id, start_date, end_date).order("sales_details.id DESC") : SalesDetail.find_by_sql("SELECT sales_details.* FROM sales_details INNER JOIN sales ON sales_details.sale_id = sales.id INNER JOIN open_cash_registers ON sales.open_cash_register_id = open_cash_registers.id INNER JOIN cash_registers ON open_cash_registers.cash_register_id = cash_registers.id WHERE ( sales.status > 1 AND sales_details.product_id = #{product_id} and sales.date_sale BETWEEN '#{start_date}' AND '#{end_date}') ORDER BY sales_details.ID DESC")
  266. @purchases = pointsale_id.present? ? PurchaseDetail.joins(:purchase).where('purchases.pointsale_id = ? AND purchases.status != 1 and purchase_details.product_id = ? and purchases.purchase_date BETWEEN ? AND ?', pointsale_id, product_id, start_date, end_date).order('purchase_details.id DESC') : PurchaseDetail.find_by_sql("SELECT purchase_details.* FROM purchase_details INNER JOIN purchases ON purchase_details.purchase_id = purchases.id WHERE ( purchases.status != 1 AND purchase_details.product_id = #{product_id} and purchases.purchase_date BETWEEN '#{start_date}' AND '#{end_date}') ORDER BY purchase_details.ID DESC")
  267. @total_quantity = pointsale_id.present? ? @sales.sum(:quantity) : ActiveRecord::Base.connection.select_value("SELECT SUM(quantity) as quantity FROM sales LEFT OUTER JOIN sales_details ON sales_details.sale_id = sales.id WHERE (sales.status > 1 and sales_details.product_id = #{product_id} and sales.date_sale BETWEEN '#{start_date}' AND '#{end_date}')")
  268. @total_quantity_purchases = pointsale_id.present? ? @purchases.sum(:quantity) : ActiveRecord::Base.connection.select_value("SELECT SUM(quantity) as quantity FROM purchases LEFT OUTER JOIN purchase_details ON purchase_details.purchase_id = purchases.id WHERE (purchases.status != 1 and purchase_details.product_id = #{product_id} and purchases.purchase_date BETWEEN '#{start_date}' AND '#{end_date}')")
  269. @total_sales = pointsale_id.present? ? @sales.sum(:total) : ActiveRecord::Base.connection.select_value("SELECT SUM(sales.total) as total FROM sales LEFT OUTER JOIN sales_details ON sales_details.sale_id = sales.id WHERE (sales.status > 1 and sales_details.product_id = #{product_id})")
  270. format.js
  271. end
  272. end
  273. end
  274. def labels_list
  275. @product = Product.find(params[:product_id])
  276. if @product.presentation
  277. @pointsales = @product.get_available_children(true)
  278. end
  279. end
  280. def print_labels
  281. @products = JSON.parse params[:products]
  282. @pointsale_id = params[:pointsale_id]
  283. @products.each do |obj|
  284. obj['product'] = Product.find(obj['id'])
  285. obj['price'] = @pointsale_id.present? ? obj['product'].get_price_sale(@pointsale_id) : obj['product'].price_sale
  286. end
  287. file_name = "etiquetas_#{Time.now.to_i}"
  288. pdf = render_to_string pdf: file_name, template: "products/print_labels.pdf.erb", layout: 'labels.html.erb', locals: { objs: @products }, show_as_html: params.key?('debug'), page_width: '62mm', page_height: '300mm'
  289. save_path = Rails.public_path.join("pdfs", "#{file_name}.pdf")
  290. File.open(save_path, 'wb') do |file|
  291. file << pdf
  292. end
  293. respond_to do |format|
  294. format.js { render action: "print_labels", locals: { pdf_path: "pdfs/#{file_name}.pdf" } }
  295. end
  296. end
  297. private
  298. # Use callbacks to share common setup or constraints between actions.
  299. def set_product
  300. @product = Product.find(params[:id])
  301. end
  302. def set_product_id
  303. @product = Product.find(params[:product_id])
  304. end
  305. def get_filters
  306. @current_page = params[:current_page].blank? ? 1 : params[:current_page]
  307. @filter = params[:filter]
  308. end
  309. # Never trust parameters from the scary internet, only allow the white list through.
  310. def product_params
  311. params.require(:product).permit(:sku, :name, :description, :price_base, :price_sale, :img_product, :img_product_cache, :presentation, :inventory, :unit_id, :content, :status, :categorias, :category_ids, :include_purchase_tax, :include_sale_tax, :barcode, :is_in_dollars, :price_base_dollars, size_list: [], color_list: [], style_list: [], available_products_attributes: [:id, :price_sale])
  312. end
  313. def get_categories
  314. @categories = Array.new
  315. unless params[:product][:category_ids].blank?
  316. @categories << Category.find(params[:product][:category_ids])
  317. @product.categories = @categories
  318. end
  319. end
  320. def save_pre_purchase(product)
  321. @pre_purchase = PrePurchase.new
  322. @pre_purchase.supplier_id = params[:supplier]
  323. @pre_purchase.pointsale_id = params[:pointsale] if params[:pointsale].present?
  324. @pre_purchase.warehouse_id = params[:warehouse] if params[:warehouse].present?
  325. @pre_purchase.exchange = params[:exchange] if params[:exchange].present?
  326. @pre_purchase.user_id = current_user.id
  327. @pre_purchase.product_id = product.id
  328. @pre_purchase.quantity = 1
  329. @pre_purchase.get_totals
  330. @pre_purchase.save
  331. end
  332. def set_available
  333. ##--- agregar a productos disponibles ya sea punto de venta o almacen
  334. if params[:pointsale].present?
  335. available_product = AvailableProduct.new
  336. available_product.pointsale_id = @pre_purchase.pointsale_id
  337. else
  338. available_product = WarehouseStock.new
  339. available_product.warehouse_id = @pre_purchase.warehouse_id
  340. end
  341. available_product.product_id = @pre_purchase.product_id
  342. available_product.stock_min = params[:stock_min]
  343. available_product.stock_max = params[:stock_max]
  344. available_product.save
  345. end
  346. def get_attrs
  347. @attrs = Array.new
  348. @product.variants_attributes.each do |attri|
  349. @attrs << attri.context
  350. end
  351. end
  352. end