products_controller.rb 16 KB

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