Commit c99dd6dac26cff00c91a6a1b2f840b2788949628
1 parent
6a38c0b2
Exists in
master
and in
29 other branches
Add new consumption plugins
This patch adds 3 new consumption plugins: * orders_cycle * suppliers * volunteers These plugins are not properly tested yet but they are necessary for the orders and delivery plugins (that are properly tested) to work corretctly.
Showing
237 changed files
with
8301 additions
and
0 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 237 files displayed.
plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_admin_item_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,17 @@ |
1 | +class OrdersCyclePluginAdminItemController < OrdersPluginAdminItemController | |
2 | + | |
3 | + no_design_blocks | |
4 | + | |
5 | + # FIXME: remove me when styles move from consumers_coop plugin | |
6 | + include ConsumersCoopPlugin::ControllerHelper | |
7 | + include OrdersCyclePlugin::TranslationHelper | |
8 | + | |
9 | + helper OrdersCyclePlugin::TranslationHelper | |
10 | + helper OrdersCyclePlugin::DisplayHelper | |
11 | + | |
12 | + protected | |
13 | + | |
14 | + extend HMVC::ClassMethods | |
15 | + hmvc OrdersCyclePlugin, orders_context: OrdersCyclePlugin | |
16 | + | |
17 | +end | ... | ... |
plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_cycle_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,156 @@ |
1 | +class OrdersCyclePluginCycleController < OrdersPluginAdminController | |
2 | + | |
3 | + no_design_blocks | |
4 | + | |
5 | + # FIXME: remove me when styles move from consumers_coop plugin | |
6 | + include ConsumersCoopPlugin::ControllerHelper | |
7 | + include OrdersCyclePlugin::TranslationHelper | |
8 | + | |
9 | + protect 'edit_profile', :profile | |
10 | + before_filter :set_admin | |
11 | + | |
12 | + helper OrdersCyclePlugin::TranslationHelper | |
13 | + helper OrdersCyclePlugin::DisplayHelper | |
14 | + | |
15 | + def index | |
16 | + @closed_cycles = search_scope(profile.orders_cycles.closing).all | |
17 | + if request.xhr? | |
18 | + render partial: 'results' | |
19 | + else | |
20 | + @open_cycles = profile.orders_cycles.opened | |
21 | + end | |
22 | + end | |
23 | + | |
24 | + def new | |
25 | + if request.put? | |
26 | + @cycle = OrdersCyclePlugin::Cycle.find params[:id] | |
27 | + | |
28 | + params[:cycle][:status] = 'orders' if @open = params[:open] == '1' | |
29 | + @success = @cycle.update_attributes params[:cycle] | |
30 | + | |
31 | + if @success | |
32 | + session[:notice] = t('controllers.myprofile.cycle_controller.cycle_created') | |
33 | + if params[:sendmail] | |
34 | + OrdersCyclePlugin::Mailer.delay(run_at: @cycle.start).open_cycle( | |
35 | + @cycle.profile, @cycle ,t('controllers.myprofile.cycle_controller.new_open_cycle')+": "+@cycle.name, @cycle.opening_message) | |
36 | + end | |
37 | + else | |
38 | + render action: :edit | |
39 | + end | |
40 | + else | |
41 | + count = OrdersCyclePlugin::Cycle.count conditions: {profile_id: profile} | |
42 | + @cycle = OrdersCyclePlugin::Cycle.create! profile: profile, status: 'new', | |
43 | + name: t('controllers.myprofile.cycle_controller.cycle_n_n') % {n: count+1} | |
44 | + end | |
45 | + end | |
46 | + | |
47 | + def edit | |
48 | + # editing an order | |
49 | + return super if params[:actor_name] | |
50 | + | |
51 | + @cycle = OrdersCyclePlugin::Cycle.find params[:id] | |
52 | + @products = products | |
53 | + | |
54 | + if request.xhr? | |
55 | + if params[:commit] | |
56 | + params[:cycle][:status] = 'orders' if @open = params[:open] == '1' | |
57 | + @success = @cycle.update_attributes params[:cycle] | |
58 | + | |
59 | + if params[:sendmail] | |
60 | + OrdersCyclePlugin::Mailer.delay(run_at: @cycle.start).open_cycle(@cycle.profile, | |
61 | + @cycle, t('controllers.myprofile.cycle_controller.new_open_cycle')+": "+@cycle.name, @cycle.opening_message) | |
62 | + end | |
63 | + end | |
64 | + end | |
65 | + end | |
66 | + | |
67 | + def products_load | |
68 | + @cycle = OrdersCyclePlugin::Cycle.find params[:id] | |
69 | + @products = products | |
70 | + | |
71 | + if @cycle.add_products_job | |
72 | + render nothing: true | |
73 | + else | |
74 | + render partial: 'product_lines' | |
75 | + end | |
76 | + end | |
77 | + | |
78 | + def destroy | |
79 | + @cycle = OrdersCyclePlugin::Cycle.find params[:id] | |
80 | + @cycle.destroy | |
81 | + redirect_to action: :index | |
82 | + end | |
83 | + | |
84 | + def step | |
85 | + @cycle = OrdersCyclePlugin::Cycle.find params[:id] | |
86 | + @cycle.step | |
87 | + @cycle.save! | |
88 | + redirect_to action: :edit, id: @cycle.id | |
89 | + end | |
90 | + | |
91 | + def step_back | |
92 | + @cycle = OrdersCyclePlugin::Cycle.find params[:id] | |
93 | + @cycle.step_back | |
94 | + @cycle.save! | |
95 | + redirect_to action: :edit, id: @cycle.id | |
96 | + end | |
97 | + | |
98 | + def add_missing_products | |
99 | + @cycle = OrdersCyclePlugin::Cycle.find params[:id] | |
100 | + @cycle.add_products | |
101 | + render partial: 'suppliers_plugin/shared/pagereload' | |
102 | + end | |
103 | + | |
104 | + def report_products | |
105 | + return super if params[:ids].present? | |
106 | + @cycle = OrdersCyclePlugin::Cycle.find params[:id] | |
107 | + report_file = report_products_by_supplier @cycle.supplier_products_by_suppliers(@cycle.sales.ordered) | |
108 | + | |
109 | + send_file report_file, type: 'application/xlsx', | |
110 | + disposition: 'attachment', | |
111 | + filename: t('controllers.myprofile.admin.products_report') % { | |
112 | + date: DateTime.now.strftime("%Y-%m-%d"), profile_identifier: profile.identifier, name: @cycle.name_with_code} | |
113 | + end | |
114 | + | |
115 | + def report_orders | |
116 | + return super if params[:ids].present? | |
117 | + @cycle = OrdersCyclePlugin::Cycle.find params[:id] | |
118 | + report_file = report_orders_by_consumer @cycle.sales.ordered | |
119 | + | |
120 | + send_file report_file, type: 'application/xlsx', | |
121 | + disposition: 'attachment', | |
122 | + filename: t('controllers.myprofile.admin.orders_report') % {date: DateTime.now.strftime("%Y-%m-%d"), profile_identifier: profile.identifier, name: @cycle.name_with_code} | |
123 | + end | |
124 | + | |
125 | + def filter | |
126 | + @cycle = profile.orders_cycles.find params[:owner_id] | |
127 | + @scope = @cycle | |
128 | + | |
129 | + params[:code].gsub!(/^#{@cycle.code}\./, '') if params[:code].present? | |
130 | + super | |
131 | + end | |
132 | + | |
133 | + protected | |
134 | + | |
135 | + attr_accessor :cycle | |
136 | + | |
137 | + extend HMVC::ClassMethods | |
138 | + hmvc OrdersCyclePlugin, orders_context: OrdersCyclePlugin | |
139 | + | |
140 | + def search_scope scope | |
141 | + params[:date] ||= {} | |
142 | + scope = scope.by_year params[:date][:year] if params[:date][:year].present? | |
143 | + scope = scope.by_month params[:date][:month] if params[:date][:month].present? | |
144 | + scope = scope.by_status params[:status] if params[:status].present? | |
145 | + scope | |
146 | + end | |
147 | + | |
148 | + def set_admin | |
149 | + @admin = true | |
150 | + end | |
151 | + | |
152 | + def products | |
153 | + @cycle.products.unarchived.paginate per_page: 15, page: params["page"] | |
154 | + end | |
155 | + | |
156 | +end | ... | ... |
plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_delivery_option_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,17 @@ |
1 | +class OrdersCyclePluginDeliveryOptionController < DeliveryPlugin::AdminOptionsController | |
2 | + | |
3 | + no_design_blocks | |
4 | + | |
5 | + # FIXME: remove me when styles move from consumers_coop plugin | |
6 | + include ConsumersCoopPlugin::ControllerHelper | |
7 | + include OrdersCyclePlugin::TranslationHelper | |
8 | + | |
9 | + helper OrdersCyclePlugin::TranslationHelper | |
10 | + helper OrdersCyclePlugin::DisplayHelper | |
11 | + | |
12 | + protected | |
13 | + | |
14 | + extend HMVC::ClassMethods | |
15 | + hmvc OrdersCyclePlugin, orders_context: OrdersCyclePlugin | |
16 | + | |
17 | +end | ... | ... |
plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_item_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,67 @@ |
1 | +class OrdersCyclePluginItemController < OrdersPluginItemController | |
2 | + | |
3 | + no_design_blocks | |
4 | + | |
5 | + # FIXME: remove me when styles move from consumers_coop plugin | |
6 | + include ConsumersCoopPlugin::ControllerHelper | |
7 | + include OrdersCyclePlugin::TranslationHelper | |
8 | + | |
9 | + helper OrdersCyclePlugin::TranslationHelper | |
10 | + helper OrdersCyclePlugin::DisplayHelper | |
11 | + | |
12 | + def new | |
13 | + @offered_product = Product.find params[:offered_product_id] | |
14 | + @consumer = user | |
15 | + return render_not_found unless @offered_product | |
16 | + raise 'Please login to place an order' if @consumer.blank? | |
17 | + | |
18 | + if params[:order_id] == 'new' | |
19 | + @cycle = @offered_product.cycle | |
20 | + raise 'Cycle closed for orders' unless @cycle.may_order? @consumer | |
21 | + @order = OrdersCyclePlugin::Sale.create! cycle: @cycle, profile: profile, consumer: @consumer | |
22 | + else | |
23 | + @order = OrdersCyclePlugin::Sale.find params[:order_id] | |
24 | + @cycle = @order.cycle | |
25 | + raise 'Order confirmed or cycle is closed for orders' unless @order.open? | |
26 | + raise 'You are not the owner of this order' unless @order.may_edit? @consumer, @admin | |
27 | + end | |
28 | + | |
29 | + @item = OrdersCyclePlugin::Item.where(order_id: @order.id, product_id: @offered_product.id).first | |
30 | + @item ||= OrdersCyclePlugin::Item.new | |
31 | + @item.sale = @order | |
32 | + @item.product = @offered_product | |
33 | + if set_quantity_consumer_ordered(params[:quantity_consumer_ordered] || 1) | |
34 | + @item.update_attributes! quantity_consumer_ordered: @quantity_consumer_ordered | |
35 | + end | |
36 | + end | |
37 | + | |
38 | + def edit | |
39 | + return redirect_to params.merge(action: :admin_edit) if @admin_edit | |
40 | + super | |
41 | + @offered_product = @item.product | |
42 | + @cycle = @order.cycle | |
43 | + end | |
44 | + | |
45 | + def admin_edit | |
46 | + @item = OrdersCyclePlugin::Item.find params[:id] | |
47 | + @order = @item.order | |
48 | + @cycle = @order.cycle | |
49 | + | |
50 | + #update on association for total | |
51 | + @order.items.each{ |i| i.attributes = params[:item] if i.id == @item.id } | |
52 | + | |
53 | + @item.update_attributes = params[:item] | |
54 | + end | |
55 | + | |
56 | + def destroy | |
57 | + super | |
58 | + @offered_product = @product | |
59 | + @cycle = @order.cycle | |
60 | + end | |
61 | + | |
62 | + protected | |
63 | + | |
64 | + extend HMVC::ClassMethods | |
65 | + hmvc OrdersCyclePlugin, orders_context: OrdersCyclePlugin | |
66 | + | |
67 | +end | ... | ... |
plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_message_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,14 @@ |
1 | +class OrdersCyclePluginMessageController < OrdersPluginMessageController | |
2 | + | |
3 | + no_design_blocks | |
4 | + | |
5 | + # FIXME: remove me when styles move from consumers_coop plugin | |
6 | + include ConsumersCoopPlugin::ControllerHelper | |
7 | + include OrdersCyclePlugin::TranslationHelper | |
8 | + | |
9 | + helper OrdersCyclePlugin::TranslationHelper | |
10 | + helper OrdersPlugin::FieldHelper | |
11 | + | |
12 | + protected | |
13 | + | |
14 | +end | ... | ... |
plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_product_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,46 @@ |
1 | +class OrdersCyclePluginProductController < SuppliersPlugin::ProductController | |
2 | + | |
3 | + no_design_blocks | |
4 | + | |
5 | + # FIXME: remove me when styles move from consumers_coop plugin | |
6 | + include ConsumersCoopPlugin::ControllerHelper | |
7 | + include OrdersCyclePlugin::TranslationHelper | |
8 | + | |
9 | + helper OrdersCyclePlugin::TranslationHelper | |
10 | + helper OrdersCyclePlugin::DisplayHelper | |
11 | + | |
12 | + def edit | |
13 | + super | |
14 | + @units = environment.units.all | |
15 | + end | |
16 | + | |
17 | + def remove_from_order | |
18 | + @offered_product = OrdersCyclePlugin::OfferedProduct.find params[:id] | |
19 | + @order = OrdersCyclePlugin::Sale.find params[:order_id] | |
20 | + raise 'Order confirmed or cycle is closed for orders' unless @order.open? | |
21 | + @item = @order.items.find_by_product_id @offered_product.id | |
22 | + @item.destroy rescue render nothing: true | |
23 | + end | |
24 | + | |
25 | + def cycle_edit | |
26 | + @product = OrdersCyclePlugin::OfferedProduct.find params[:id] | |
27 | + if request.xhr? | |
28 | + @product.update_attributes! params[:product] | |
29 | + respond_to do |format| | |
30 | + format.js | |
31 | + end | |
32 | + end | |
33 | + end | |
34 | + | |
35 | + def cycle_destroy | |
36 | + @product = OrdersCyclePlugin::OfferedProduct.find params[:id] | |
37 | + @product.destroy | |
38 | + flash[:notice] = t('controllers.myprofile.product_controller.product_removed_from_') | |
39 | + end | |
40 | + | |
41 | + protected | |
42 | + | |
43 | + extend HMVC::ClassMethods | |
44 | + hmvc OrdersCyclePlugin, orders_context: OrdersCyclePlugin | |
45 | + | |
46 | +end | ... | ... |
plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_supplier_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,24 @@ |
1 | +class OrdersCyclePluginSupplierController < SuppliersPluginMyprofileController | |
2 | + | |
3 | + no_design_blocks | |
4 | + | |
5 | + # FIXME: remove me when styles move from consumers_coop plugin | |
6 | + include ConsumersCoopPlugin::ControllerHelper | |
7 | + include OrdersCyclePlugin::TranslationHelper | |
8 | + | |
9 | + protect 'edit_profile', :profile | |
10 | + | |
11 | + helper OrdersCyclePlugin::TranslationHelper | |
12 | + helper OrdersCyclePlugin::DisplayHelper | |
13 | + | |
14 | + def margin_change | |
15 | + super | |
16 | + profile.orders_cycles_products_default_margins if params[:apply_to_open_cycles] | |
17 | + end | |
18 | + | |
19 | + protected | |
20 | + | |
21 | + extend HMVC::ClassMethods | |
22 | + hmvc OrdersCyclePlugin, orders_context: OrdersCyclePlugin | |
23 | + | |
24 | +end | ... | ... |
plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_volunteers_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,13 @@ |
1 | +class OrdersCyclePluginVolunteersController < VolunteersPluginMyprofileController | |
2 | + | |
3 | + no_design_blocks | |
4 | + include OrdersCyclePlugin::TranslationHelper | |
5 | + | |
6 | + helper OrdersCyclePlugin::TranslationHelper | |
7 | + | |
8 | + protected | |
9 | + | |
10 | + extend HMVC::ClassMethods | |
11 | + hmvc OrdersCyclePlugin, orders_context: OrdersCyclePlugin | |
12 | + | |
13 | +end | ... | ... |
plugins/orders_cycle/controllers/profile/orders_cycle_plugin_order_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,183 @@ |
1 | +class OrdersCyclePluginOrderController < OrdersPluginOrderController | |
2 | + | |
3 | + # FIXME: remove me when styles move from consumers_coop plugin | |
4 | + include ConsumersCoopPlugin::ControllerHelper | |
5 | + include OrdersCyclePlugin::TranslationHelper | |
6 | + | |
7 | + no_design_blocks | |
8 | + before_filter :login_required, except: [:index] | |
9 | + | |
10 | + helper OrdersCyclePlugin::TranslationHelper | |
11 | + helper OrdersCyclePlugin::DisplayHelper | |
12 | + | |
13 | + def index | |
14 | + @current_year = DateTime.now.year.to_s | |
15 | + @year = (params[:year] || @current_year).to_s | |
16 | + | |
17 | + @years_with_cycles = profile.orders_cycles_without_order.years.collect &:year | |
18 | + @years_with_cycles.unshift @current_year unless @years_with_cycles.include? @current_year | |
19 | + | |
20 | + @cycles = profile.orders_cycles.by_year @year | |
21 | + @consumer = user | |
22 | + end | |
23 | + | |
24 | + def new | |
25 | + if user.blank? | |
26 | + session[:notice] = t('orders_plugin.controllers.profile.consumer.please_login_first') | |
27 | + redirect_to action: :index | |
28 | + return | |
29 | + end | |
30 | + | |
31 | + if not profile.members.include? user | |
32 | + render_access_denied | |
33 | + else | |
34 | + @consumer = user | |
35 | + @cycle = profile.orders_cycles.find params[:cycle_id] | |
36 | + @order = OrdersCyclePlugin::Sale.new | |
37 | + @order.profile = profile | |
38 | + @order.consumer = @consumer | |
39 | + @order.cycle = @cycle | |
40 | + @order.save! | |
41 | + redirect_to params.merge(action: :edit, id: @order.id) | |
42 | + end | |
43 | + end | |
44 | + | |
45 | + def repeat | |
46 | + @consumer = user | |
47 | + @order = profile.orders_cycles_sales.where(id: params[:order_id], consumer_id: @consumer.id).first | |
48 | + @cycle = profile.orders_cycles.find params[:cycle_id] | |
49 | + if @order | |
50 | + @order.repeat_cycle = @cycle | |
51 | + @repeat_order = OrdersCyclePlugin::Sale.new profile: profile, consumer: @consumer, cycle: @cycle | |
52 | + @order.items.each do |item| | |
53 | + next unless item.repeat_product and item.repeat_product.available | |
54 | + @repeat_order.items.build sale: @repeat_order, product: item.repeat_product, quantity_consumer_ordered: item.quantity_consumer_ordered | |
55 | + end | |
56 | + @repeat_order.supplier_delivery = @order.supplier_delivery | |
57 | + @repeat_order.save! | |
58 | + redirect_to params.merge(action: :edit, id: @repeat_order.id) | |
59 | + else | |
60 | + @orders = @cycle.consumer_previous_orders(@consumer).last(5).reverse | |
61 | + @orders.each{ |o| o.enable_product_diff } | |
62 | + @orders.each{ |o| o.repeat_cycle = @cycle } | |
63 | + render template: 'orders_plugin/repeat' | |
64 | + end | |
65 | + end | |
66 | + | |
67 | + def edit | |
68 | + return show_more if params[:page].present? | |
69 | + | |
70 | + if request.xhr? and params[:order].present? | |
71 | + status = params[:order][:status] | |
72 | + if status == 'ordered' | |
73 | + if @order.items.size > 0 | |
74 | + @order.to_yaml # most strange workaround to avoid a crash in the next line | |
75 | + @order.update_attributes! params[:order] | |
76 | + session[:notice] = t('orders_plugin.controllers.profile.consumer.order_confirmed') | |
77 | + else | |
78 | + session[:notice] = t('orders_plugin.controllers.profile.consumer.can_not_confirm_your_') | |
79 | + end | |
80 | + end | |
81 | + return | |
82 | + end | |
83 | + | |
84 | + if cycle_id = params[:cycle_id] | |
85 | + @cycle = profile.orders_cycles.where(id: cycle_id).first | |
86 | + return render_not_found unless @cycle | |
87 | + @consumer = user | |
88 | + | |
89 | + # load the first order | |
90 | + unless @order | |
91 | + @consumer_orders = @cycle.sales.for_consumer @consumer | |
92 | + if @consumer_orders.size == 1 | |
93 | + @order = @consumer_orders.first | |
94 | + redirect_to action: :edit, id: @order.id | |
95 | + elsif @consumer_orders.size > 1 | |
96 | + # get the first open | |
97 | + @order = @consumer_orders.find{ |o| o.open? } | |
98 | + redirect_to action: :edit, id: @order.id if @order | |
99 | + end | |
100 | + end | |
101 | + else | |
102 | + return render_not_found unless @order | |
103 | + # an order was loaded on load_order | |
104 | + | |
105 | + @cycle = @order.cycle | |
106 | + | |
107 | + @consumer = @order.consumer | |
108 | + @admin_edit = (user and user.in?(profile.admins) and user != @consumer) | |
109 | + return render_access_denied unless @user_is_admin or @admin_edit or user == @consumer | |
110 | + | |
111 | + @consumer_orders = @cycle.sales.for_consumer @consumer | |
112 | + end | |
113 | + | |
114 | + load_products_for_order | |
115 | + @product_categories = @cycle.product_categories | |
116 | + @consumer_orders = @cycle.sales.for_consumer @consumer | |
117 | + end | |
118 | + | |
119 | + def reopen | |
120 | + @order.update_attributes! status: 'draft' | |
121 | + render 'edit' | |
122 | + end | |
123 | + | |
124 | + def cancel | |
125 | + @order.update_attributes! status: 'cancelled' | |
126 | + session[:notice] = t('orders_plugin.controllers.profile.consumer.order_cancelled') | |
127 | + render 'edit' | |
128 | + end | |
129 | + | |
130 | + def remove | |
131 | + super | |
132 | + redirect_to action: :index, cycle_id: @order.cycle.id | |
133 | + end | |
134 | + | |
135 | + def admin_new | |
136 | + return redirect_to action: :index unless profile.has_admin? user | |
137 | + | |
138 | + @consumer = user | |
139 | + @cycle = profile.orders_cycles.find params[:cycle_id] | |
140 | + @order = OrdersCyclePlugin::Sale.create! cycle: @cycle, consumer: @consumer | |
141 | + redirect_to action: :edit, id: @order.id, profile: profile.identifier | |
142 | + end | |
143 | + | |
144 | + def filter | |
145 | + if id = params[:id] | |
146 | + @order = OrdersCyclePlugin::Sale.find id rescue nil | |
147 | + @cycle = @order.cycle | |
148 | + else | |
149 | + @cycle = profile.orders_cycles.find params[:cycle_id] | |
150 | + @order = OrdersCyclePlugin::Sale.find params[:order_id] rescue nil | |
151 | + end | |
152 | + load_products_for_order | |
153 | + | |
154 | + render partial: 'filter', locals: { | |
155 | + order: @order, cycle: @cycle, | |
156 | + products_for_order: @products, | |
157 | + } | |
158 | + end | |
159 | + | |
160 | + def show_more | |
161 | + filter | |
162 | + end | |
163 | + | |
164 | + def supplier_balloon | |
165 | + @supplier = SuppliersPlugin::Supplier.find params[:id] | |
166 | + end | |
167 | + def product_balloon | |
168 | + @product = OrdersCyclePlugin::OfferedProduct.find params[:id] | |
169 | + end | |
170 | + | |
171 | + protected | |
172 | + | |
173 | + def load_products_for_order | |
174 | + scope = @cycle.products_for_order | |
175 | + page, per_page = params[:page].to_i, 20 | |
176 | + page = 1 if page < 1 | |
177 | + @products = OrdersCyclePlugin::OfferedProduct.search_scope(scope, params).paginate page: page, per_page: per_page | |
178 | + end | |
179 | + | |
180 | + extend HMVC::ClassMethods | |
181 | + hmvc OrdersCyclePlugin, orders_context: OrdersCyclePlugin | |
182 | + | |
183 | +end | ... | ... |
plugins/orders_cycle/db/migrate/20130909175738_create_orders_cycle_plugin_tables.rb
0 → 100644
... | ... | @@ -0,0 +1,39 @@ |
1 | +class CreateOrdersCyclePluginTables < ActiveRecord::Migration | |
2 | + | |
3 | + def change | |
4 | + # check if distribution plugin already moved the table | |
5 | + return if ActiveRecord::Base.connection.table_exists? :orders_cycle_plugin_cycles | |
6 | + | |
7 | + create_table :orders_cycle_plugin_cycle_orders do |t| | |
8 | + t.integer :cycle_id | |
9 | + t.integer :order_id | |
10 | + t.datetime :created_at | |
11 | + t.datetime :updated_at | |
12 | + end | |
13 | + | |
14 | + create_table :orders_cycle_plugin_cycle_products do |t| | |
15 | + t.integer :cycle_id | |
16 | + t.integer :product_id | |
17 | + end | |
18 | + | |
19 | + create_table :orders_cycle_plugin_cycles do |t| | |
20 | + t.integer :profile_id | |
21 | + t.integer :code | |
22 | + t.string :name | |
23 | + t.text :description | |
24 | + t.datetime :start | |
25 | + t.datetime :finish | |
26 | + t.string :status | |
27 | + t.text :opening_message | |
28 | + t.datetime :delivery_start | |
29 | + t.datetime :delivery_finish | |
30 | + t.decimal :margin_percentage | |
31 | + t.datetime :created_at | |
32 | + t.datetime :updated_at | |
33 | + end | |
34 | + | |
35 | + add_index :orders_cycle_plugin_cycles, [:profile_id] | |
36 | + add_index :orders_cycle_plugin_cycles, [:status] | |
37 | + end | |
38 | + | |
39 | +end | ... | ... |
plugins/orders_cycle/db/migrate/20131001162741_orders_cycle_plugin_index_filtered_fields.rb
0 → 100644
... | ... | @@ -0,0 +1,19 @@ |
1 | +class OrdersCyclePluginIndexFilteredFields < ActiveRecord::Migration | |
2 | + | |
3 | + def up | |
4 | + add_index :orders_cycle_plugin_cycle_orders, [:cycle_id] | |
5 | + add_index :orders_cycle_plugin_cycle_orders, [:order_id] | |
6 | + add_index :orders_cycle_plugin_cycle_orders, [:cycle_id, :order_id] | |
7 | + | |
8 | + add_index :orders_cycle_plugin_cycle_products, [:cycle_id], name: :orders_cycle_plugin_index_dqaEe7Hf | |
9 | + add_index :orders_cycle_plugin_cycle_products, [:product_id], name: :orders_cycle_plugin_index_f5DmQ6w5Y | |
10 | + add_index :orders_cycle_plugin_cycle_products, [:cycle_id, :product_id], name: :orders_cycle_plugin_index_PhBVTRFB | |
11 | + | |
12 | + add_index :orders_cycle_plugin_cycles, [:code] | |
13 | + end | |
14 | + | |
15 | + def down | |
16 | + say "this migration can't be reverted" | |
17 | + end | |
18 | + | |
19 | +end | ... | ... |
plugins/orders_cycle/db/migrate/20140406155248_refactor_orders_cycle_plugin_cycle_order.rb
0 → 100644
... | ... | @@ -0,0 +1,17 @@ |
1 | +class RefactorOrdersCyclePluginCycleOrder < ActiveRecord::Migration | |
2 | + | |
3 | + def up | |
4 | + rename_column :orders_cycle_plugin_cycle_orders, :order_id, :sale_id | |
5 | + add_column :orders_cycle_plugin_cycle_orders, :purchase_id, :integer | |
6 | + | |
7 | + add_index :orders_cycle_plugin_cycle_orders, :sale_id | |
8 | + add_index :orders_cycle_plugin_cycle_orders, :purchase_id | |
9 | + add_index :orders_cycle_plugin_cycle_orders, [:cycle_id, :sale_id] | |
10 | + add_index :orders_cycle_plugin_cycle_orders, [:cycle_id, :purchase_id], name: :index_orders_cycle_plugin_cycle_orders_cycle_purchase | |
11 | + end | |
12 | + | |
13 | + def down | |
14 | + say "this migration can't be reverted" | |
15 | + end | |
16 | + | |
17 | +end | ... | ... |
plugins/orders_cycle/db/migrate/20140911210514_add_serialized_data_to_orders_cycle_plugin_cycle.rb
0 → 100644
... | ... | @@ -0,0 +1,10 @@ |
1 | +class AddSerializedDataToOrdersCyclePluginCycle < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + add_column :orders_cycle_plugin_cycles, :data, :text, :default => {}.to_yaml | |
4 | + execute "update orders_cycle_plugin_cycles set data = '#{{}.to_yaml}'" | |
5 | + end | |
6 | + | |
7 | + def self.down | |
8 | + remove_column :orders_cycle_plugin_cycles, :data | |
9 | + end | |
10 | +end | ... | ... |
plugins/orders_cycle/db/migrate/20150119173244_move_items_to_orders_cycle_plugin_item.rb
0 → 100644
... | ... | @@ -0,0 +1,12 @@ |
1 | +class MoveItemsToOrdersCyclePluginItem < ActiveRecord::Migration | |
2 | + def up | |
3 | + OrdersCyclePlugin::Cycle.find_each batch_size: 5 do |cycle| | |
4 | + cycle.items_selled.update_all type: 'OrdersCyclePlugin::Item' | |
5 | + cycle.items_purchased.update_all type: 'OrdersCyclePlugin::Item' | |
6 | + end | |
7 | + end | |
8 | + | |
9 | + def down | |
10 | + say "this migration can't be reverted" | |
11 | + end | |
12 | +end | ... | ... |
plugins/orders_cycle/db/migrate/20150506220607_fill_default_delivery_method_to_orders_cycle_sales.rb
0 → 100644
... | ... | @@ -0,0 +1,12 @@ |
1 | +class FillDefaultDeliveryMethodToOrdersCycleSales < ActiveRecord::Migration | |
2 | + def up | |
3 | + OrdersCyclePlugin::Sale.find_each batch_size: 50 do |sale| | |
4 | + next unless sale.cycle.present? | |
5 | + sale.update_column :supplier_delivery_id, sale.supplier_delivery_id | |
6 | + end | |
7 | + end | |
8 | + | |
9 | + def down | |
10 | + say "this migration can't be reverted" | |
11 | + end | |
12 | +end | ... | ... |
... | ... | @@ -0,0 +1,8 @@ |
1 | +require_dependency 'delivery_plugin/option' | |
2 | + | |
3 | +class DeliveryPlugin::Option | |
4 | + | |
5 | + belongs_to :cycle, class_name: 'OrdersCyclePlugin::Cycle', | |
6 | + foreign_key: :owner_id, conditions: ["delivery_plugin_options.owner_type = 'OrdersCyclePlugin::Cycle'"] | |
7 | + | |
8 | +end | ... | ... |
... | ... | @@ -0,0 +1,12 @@ |
1 | +require_dependency 'product' | |
2 | + | |
3 | +# based on orders/lib/ext/product.rb | |
4 | +class Product | |
5 | + | |
6 | + has_many :orders_cycles_items, class_name: 'OrdersCyclePlugin::Item', foreign_key: :product_id | |
7 | + | |
8 | + has_many :orders_cycles_orders, through: :orders_cycles_items, source: :order | |
9 | + has_many :orders_cycles_sales, through: :orders_cycles_items, source: :sale | |
10 | + has_many :orders_cycles_purchases, through: :orders_cycles_items, source: :purchase | |
11 | + | |
12 | +end | ... | ... |
... | ... | @@ -0,0 +1,32 @@ |
1 | +require_dependency 'profile' | |
2 | + | |
3 | +class Profile | |
4 | + | |
5 | + has_many :orders_cycles, class_name: 'OrdersCyclePlugin::Cycle', dependent: :destroy, order: 'created_at DESC', | |
6 | + conditions: ["orders_cycle_plugin_cycles.status <> 'new'"] | |
7 | + has_many :orders_cycles_without_order, class_name: 'OrdersCyclePlugin::Cycle', | |
8 | + conditions: ["orders_cycle_plugin_cycles.status <> 'new'"] | |
9 | + | |
10 | + has_many :orders_cycles_sales, through: :orders_cycles, source: :sales | |
11 | + has_many :orders_cycles_purchases, through: :orders_cycles, source: :purchases | |
12 | + | |
13 | + has_many :offered_products, class_name: 'OrdersCyclePlugin::OfferedProduct', order: 'products.name ASC' | |
14 | + | |
15 | + def orders_cycles_closed_date_range | |
16 | + list = self.orders_cycles.closing.all order: 'start ASC' | |
17 | + return DateTime.now..DateTime.now if list.blank? | |
18 | + list.first.start.to_date..list.last.finish.to_date | |
19 | + end | |
20 | + | |
21 | + def orders_cycles_products_default_margins | |
22 | + self.class.transaction do | |
23 | + self.orders_cycles.opened.each do |cycle| | |
24 | + cycle.products.each do |product| | |
25 | + product.margin_percentage = margin_percentage | |
26 | + product.save! | |
27 | + end | |
28 | + end | |
29 | + end | |
30 | + end | |
31 | + | |
32 | +end | ... | ... |
plugins/orders_cycle/lib/ext/suppliers_plugin/base_product.rb
0 → 100644
... | ... | @@ -0,0 +1,13 @@ |
1 | +module OrdersCyclePlugin | |
2 | + | |
3 | + extend Noosfero::Plugin::ParentMethods | |
4 | + | |
5 | + def self.plugin_name | |
6 | + I18n.t('orders_cycle_plugin.lib.plugin.name') | |
7 | + end | |
8 | + | |
9 | + def self.plugin_description | |
10 | + I18n.t('orders_cycle_plugin.lib.plugin.description') | |
11 | + end | |
12 | + | |
13 | +end | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +require_dependency "#{File.dirname __FILE__}/../ext/delivery_plugin/option" | |
2 | + | |
3 | +class OrdersCyclePlugin::Base < Noosfero::Plugin | |
4 | + | |
5 | + def stylesheet? | |
6 | + true | |
7 | + end | |
8 | + | |
9 | + def js_files | |
10 | + ['orders_cycle'].map{ |j| "javascripts/#{j}" } | |
11 | + end | |
12 | + | |
13 | +end | |
14 | + | ... | ... |
plugins/orders_cycle/lib/orders_cycle_plugin/cycle_helper.rb
0 → 100644
... | ... | @@ -0,0 +1,18 @@ |
1 | +module OrdersCyclePlugin::CycleHelper | |
2 | + | |
3 | + protected | |
4 | + | |
5 | + def timeline_class cycle, status, selected | |
6 | + klass = "" | |
7 | + if cycle.status == status | |
8 | + klass += " cycle-timeline-current-item" | |
9 | + elsif cycle.passed_by? status | |
10 | + klass += " cycle-timeline-passed-item" | |
11 | + else | |
12 | + klass += " cycle-timeline-next-item" | |
13 | + end | |
14 | + klass += " cycle-timeline-selected-item" if selected == status | |
15 | + klass | |
16 | + end | |
17 | + | |
18 | +end | ... | ... |
plugins/orders_cycle/lib/orders_cycle_plugin/display_helper.rb
0 → 100644
... | ... | @@ -0,0 +1,17 @@ |
1 | +module OrdersCyclePlugin::DisplayHelper | |
2 | + | |
3 | + protected | |
4 | + | |
5 | + include ::ActionView::Helpers::JavaScriptHelper # we want the original button_to_function! | |
6 | + | |
7 | + include OrdersPlugin::DisplayHelper | |
8 | + | |
9 | + include OrdersCyclePlugin::RepeatHelper | |
10 | + include OrdersCyclePlugin::CycleHelper | |
11 | + | |
12 | + include SuppliersPlugin::DisplayHelper | |
13 | + include SuppliersPlugin::ProductHelper | |
14 | + | |
15 | + include DeliveryPlugin::DisplayHelper | |
16 | + | |
17 | +end | ... | ... |
... | ... | @@ -0,0 +1,39 @@ |
1 | +class OrdersCyclePlugin::Mailer < Noosfero::Plugin::MailerBase | |
2 | + | |
3 | + include OrdersCyclePlugin::TranslationHelper | |
4 | + | |
5 | + helper ApplicationHelper | |
6 | + helper OrdersCyclePlugin::TranslationHelper | |
7 | + | |
8 | + attr_accessor :environment | |
9 | + attr_accessor :profile | |
10 | + | |
11 | + def open_cycle profile, cycle, subject, message | |
12 | + self.environment = profile.environment | |
13 | + @profile = profile | |
14 | + @cycle = cycle | |
15 | + @message = message | |
16 | + | |
17 | + mail bcc: organization_members(@profile), | |
18 | + from: environment.noreply_email, | |
19 | + reply_to: profile_recipients(@profile), | |
20 | + subject: t('lib.mailer.profile_subject') % {profile: profile.name, subject: subject} | |
21 | + end | |
22 | + | |
23 | + protected | |
24 | + | |
25 | + def profile_recipients profile | |
26 | + if profile.person? | |
27 | + profile.contact_email | |
28 | + else | |
29 | + profile.admins.map{ |p| p.contact_email } | |
30 | + end | |
31 | + end | |
32 | + | |
33 | + def organization_members profile | |
34 | + if profile.organization? | |
35 | + profile.members.map{ |p| p.contact_email } | |
36 | + end | |
37 | + end | |
38 | + | |
39 | +end | ... | ... |
plugins/orders_cycle/lib/orders_cycle_plugin/order_helper.rb
0 → 100644
plugins/orders_cycle/lib/orders_cycle_plugin/repeat_helper.rb
0 → 100644
... | ... | @@ -0,0 +1,13 @@ |
1 | +module OrdersCyclePlugin::RepeatHelper | |
2 | + | |
3 | + def repeat_checkout_order_button order | |
4 | + button :check, t('views.public.repeat.checkout'), {controller: :orders_cycle_plugin_order, action: :repeat, order_id: order.id, cycle_id: @cycle.id}, | |
5 | + class: 'repeat-checkout-order' | |
6 | + end | |
7 | + | |
8 | + def repeat_choose_order_button order | |
9 | + nil | |
10 | + end | |
11 | + | |
12 | +end | |
13 | + | ... | ... |
plugins/orders_cycle/lib/orders_cycle_plugin/translation_helper.rb
0 → 100644
... | ... | @@ -0,0 +1,12 @@ |
1 | +module OrdersCyclePlugin::TranslationHelper | |
2 | + | |
3 | + protected | |
4 | + | |
5 | + # included here to be used on controller's t calls | |
6 | + include TermsHelper | |
7 | + | |
8 | + def i18n_scope | |
9 | + ['orders_cycle_plugin', 'orders_plugin', 'suppliers_plugin', 'volunteers_plugin'] | |
10 | + end | |
11 | + | |
12 | +end | ... | ... |
... | ... | @@ -0,0 +1,259 @@ |
1 | +en-US: &en-US | |
2 | + | |
3 | + orders_cycle_plugin: | |
4 | + lib: | |
5 | + plugin: | |
6 | + name: "Orders' Cycle" | |
7 | + description: "Create and manage orders' cycle" | |
8 | + ext: | |
9 | + orders_plugin: | |
10 | + order: | |
11 | + cyclecode_ordercode: "%{cyclecode}.%{ordercode}" | |
12 | + mailer: | |
13 | + profile_subject: "[%{profile}] %{subject}" | |
14 | + order_was_changed: "[%{profile}] Your order was modificado" | |
15 | + order_block: | |
16 | + distribution_orders_c: "Distribution orders' cycles for consumers" | |
17 | + offer_cycles_for_you_: "Offer cycles for you consumers to make orders" | |
18 | + orders_cycles: "Orders' cycles" | |
19 | + controllers: | |
20 | + myprofile: | |
21 | + message_controller: | |
22 | + message_sent: "Message sent" | |
23 | + product_controller: | |
24 | + product_removed_from_: "Product removed from cycle" | |
25 | + product_removed_succe: "Product removed successfully" | |
26 | + the_product_was_not_r: "The product was not removed" | |
27 | + cycle_controller: | |
28 | + cycle_created: "Cycle created" | |
29 | + cycle_n_n: "Cycle n.%{n}" | |
30 | + new_open_cycle: "New open cycle: " | |
31 | + | |
32 | + models: | |
33 | + cycle: | |
34 | + code_name: "%{code}. %{name}" | |
35 | + delivery_period_befor: "Delivery' period before orders' period" | |
36 | + invalid_delivery_peri: "Invalid delivery' period" | |
37 | + invalid_orders_period: "Invalid orders' period" | |
38 | + statuses: | |
39 | + edition: Edition | |
40 | + orders: Orders | |
41 | + purchases: Purchases | |
42 | + receipts: Receipts | |
43 | + separation: Separation | |
44 | + delivery: Delivery | |
45 | + closing: Closing | |
46 | + views: | |
47 | + gadgets: | |
48 | + _cycle: | |
49 | + happening: Happening | |
50 | + orders_open_b_cycle: "Orders open: <b>%{cycle}</b>" | |
51 | + place_an_order: "place an order" | |
52 | + see_orders_cycle: "see orders' cycle" | |
53 | + cycles: | |
54 | + all_cycles: "all cycles" | |
55 | + mailer: | |
56 | + open_cycle: | |
57 | + a_new_cycle_is_open_c: "A new cycle is open called " | |
58 | + hello_member_of_name: "Hello consumer of %{name}," | |
59 | + the_administrator_let: "The administrator let a message about this cycle" | |
60 | + the_cycle_description: "The cycle description is.." | |
61 | + profile: | |
62 | + order: | |
63 | + _consumer_orders: | |
64 | + caution: "<strong>Caution</strong>, you are editing the orders of \"%{consumer}\". It is preferable to make small editions through the cycle's administration, this way the person will be properly warned of the updates. We recommend using this page only if you're doing the order for another person." | |
65 | + show_cancelled_orders: "show cancelled orders" | |
66 | + hide_cancelled_orders: "hide cancelled orders" | |
67 | + administration_of_thi: "Administration of this cycle" | |
68 | + before_the_closing: "(before the closing)" | |
69 | + change_order: "reopen order" | |
70 | + edit_your_orders: "Edit your orders" | |
71 | + login: login | |
72 | + new_order: "New order" | |
73 | + repeat_order: "Repetir order" | |
74 | + orders_from_another_m: "Orders from another consumer" | |
75 | + orders_from_consumer_: "Orders from \"%{consumer}\" on this cycle" | |
76 | + send_message_to_the_m: "send message to the managers" | |
77 | + sign_up: "sign up" | |
78 | + this_cycle_is_already: "This cycle is already closed." | |
79 | + this_cycle_is_not_ope: "This cycle is not open yet." | |
80 | + the_time_for_orders_is: "The orders' period for this cycle is from %{start} to %{finish}" | |
81 | + to_place_an_order_you: "To place an order you need to be logged in and registered %{terms.profile.at_article.singular}. Please %{login} or %{signup}." | |
82 | + you_haven_t_placed_an: "You haven't placed any order on this cycle yet." | |
83 | + you_still_can: "You still can:" | |
84 | + your_order_is_confirm: "Your order is confirmed and registered. Please follow the guidelines of the delivery method below, so that it happens without problems." | |
85 | + your_order_was_cancel: "Your order was cancelled." | |
86 | + your_order_wasn_t_con: "Your order wasn't confirmed and the cycle orders period already ended." | |
87 | + your_orders_on_this_c: "Your orders on this cycle" | |
88 | + associate_to_order: "Associate to make orders" | |
89 | + _filter_products: | |
90 | + active: active | |
91 | + all_the_categories: "all the categories" | |
92 | + all_the_suppliers: "all %{terms.supplier.article.plural}" | |
93 | + and_being: "and being" | |
94 | + anyone: anyone | |
95 | + bigger_than_the_stock: "bigger than the stock" | |
96 | + filter: Filter | |
97 | + in_any_state: "In any state" | |
98 | + inactive: inactive | |
99 | + product_name: "Product Name" | |
100 | + supplier: "%{terms.supplier.singular.capitalize}" | |
101 | + whose_qty_available_i: "whose qty. available is" | |
102 | + _status: | |
103 | + code_status_message: "%{code} %{status_message}" | |
104 | + open_it: "open it" | |
105 | + index: | |
106 | + code: "%{code}." | |
107 | + orders_cycles: "Orders' cycles" | |
108 | + place_an_order: "Place an order" | |
109 | + place_another_order: "Place another order" | |
110 | + there_s_no_open_sessi: "There's no open cycle" | |
111 | + your_orders: "Your orders:" | |
112 | + product: | |
113 | + _order_edit: | |
114 | + add: Add | |
115 | + cancel: cancel | |
116 | + change: Change | |
117 | + city: City | |
118 | + city_state: "%{city}/%{state}" | |
119 | + include: include | |
120 | + more_about_the_produc: "More about the producer \"%{supplier}\"" | |
121 | + no_description: "No description" | |
122 | + opening_new_order_for: "Opening new order for your product inclusion" | |
123 | + opening_order_code_fo: "Opening order %{code} for your product inclusion" | |
124 | + price_percent_price_w: "%{price} + %{percent}% = %{price_with_margin}" | |
125 | + price_s_descriptive: "price's descriptive" | |
126 | + product_image: "Product Image" | |
127 | + _order_search: | |
128 | + order_qty: "Order qty" | |
129 | + category: Category | |
130 | + producer: Producer | |
131 | + price: Price | |
132 | + product: Product | |
133 | + this_search_hasn_t_re: "This search hasn't returned any product" | |
134 | + _cycle_edit: | |
135 | + all_ordered_products: "All ordered products from this product will also be removed; you should first warn consumers that ordered this products" | |
136 | + buy_price: "Buy price" | |
137 | + buy_unit: "Buy unit" | |
138 | + cancel_updates: "cancel updates" | |
139 | + default_margin: "Default margin" | |
140 | + default_sell_price: "Default sell price" | |
141 | + edit_product: "edit product" | |
142 | + margin: Margin | |
143 | + qty_in_stock: "Qty. in stock" | |
144 | + qty_offered: "Qty. offered" | |
145 | + remove_from_cycle: "remove from cycle" | |
146 | + save: Save | |
147 | + sell_price: "Sell price" | |
148 | + sell_unit: "Sell unit" | |
149 | + cycle: | |
150 | + _brief: | |
151 | + confirmed_orders: | |
152 | + zero: "(no confirmed orders)" | |
153 | + one: "(1 confirmed order)" | |
154 | + other: "(%{count} confirmed orders)" | |
155 | + code: "%{code}." | |
156 | + delivery: Delivery | |
157 | + orders: Orders | |
158 | + _closed: | |
159 | + cycle_already_finishe: "Cycle already finished" | |
160 | + _edit_fields: | |
161 | + add_method: "Add method" | |
162 | + add_all_methods: "(add all)" | |
163 | + available_delivery_me: "Available delivery methods" | |
164 | + cancel_changes: "cancel changes" | |
165 | + remove: "remove" | |
166 | + confirm_remove: "Are you sure you want to remove this cycle?" | |
167 | + create_new_cycle: "Create new cycle" | |
168 | + deliveries_interval: "Deliveries Interval" | |
169 | + description: Description | |
170 | + general_settings: "General settings" | |
171 | + name: Name | |
172 | + notify_members_of_ope: "Notify consumer of open orders" | |
173 | + opening_message: "Opening Message" | |
174 | + orders_interval: "Orders Interval" | |
175 | + save: Save | |
176 | + save_and_open_orders: Save and open orders | |
177 | + create_and_open_orders: Create and open orders | |
178 | + this_message_will_be_: "This message will be sent by mail for the consumers %{terms.profile.from_article.singular} " | |
179 | + _edit_popin: | |
180 | + close: Close | |
181 | + cycle_editing: "Cycle editing" | |
182 | + cycle_saved: "Cycle saved." | |
183 | + _edition: | |
184 | + info: 'The edition time is gone and the cycle is already public. Actually, the cycle is in a supply call period.<br/><br/> It is still possible to edit some Cycle parameters through this page, however, beware of the risk. Some operations have different implications depending on the fase you are. When needed, you will be notified by a notification window of the consequences of the changes made.' | |
185 | + add_product: "Add product" | |
186 | + it_was_automatically_: "It was automatically created from the active products. See the list below and check for needed changes." | |
187 | + the_following_list_of: "The following list of products are available in this cycle." | |
188 | + the_products: "The products" | |
189 | + _products_loading: "The products are being loaded into the cycle." | |
190 | + _orders: | |
191 | + header_help: "In this phase the orders %{terms.consumer.from_article.plural} are received, and it is possible supervise them if by chance there is some more severe error." | |
192 | + the_orders_period_is_: "The orders period is still on, take care to edit the orders already open, it may confuse the users" | |
193 | + already_closed: "The orders period was already closed, It's not possible to edit the originals orders. In the redistribution phase it is possible to edit the order, before the delivery it also possible to edit this order." | |
194 | + _purchases: | |
195 | + header_help: "In this phase, using the received orders, the purchases for each supplier are done to supply the demand of all orders." | |
196 | + _receipts: | |
197 | + header_help: "In this phase are registered the receipts of the purchases e are edited any errors that may exist." | |
198 | + _separation: | |
199 | + header_help: "In this phase each order é separated acording to the availability of the products purchased that arrived." | |
200 | + _delivery: | |
201 | + header_help: "In this phase are registered the deliveries %{terms.consumer.to_article.plural}. This is the moment to register the changes in relation to what was separated." | |
202 | + _product_lines: | |
203 | + category: Category | |
204 | + price: Price | |
205 | + product: Product | |
206 | + qty_avail: "Qty. avail." | |
207 | + showing_pcount_produc: "Showing %{pcount} products of %{allpcount}" | |
208 | + supplier: "%{terms.supplier.singular.capitalize}" | |
209 | + _results: | |
210 | + no_cycles_to_show: "No cycles to show" | |
211 | + _timeline: | |
212 | + are_you_sure_you_want_to_reopen: "Are you sure you want to reopen the orders cycle?" | |
213 | + are_you_sure_you_want_to_close: "Are you sure you want to close the orders cycle?" | |
214 | + call: Call | |
215 | + close: Close | |
216 | + close_status: "Close %{status}" | |
217 | + finish_cycle_editing: "Open orders for cycle" | |
218 | + reopen_orders_period: "Reopen orders period" | |
219 | + _title: | |
220 | + new_cycle: "New cycle" | |
221 | + order_cycle: "Order Cycle: " | |
222 | + _view_dates: | |
223 | + delivery: "Delivery: " | |
224 | + happening: Happening | |
225 | + orders: "Orders: " | |
226 | + _view_header: | |
227 | + ? ", " | |
228 | + : ", " | |
229 | + all_orders_cycles: "all orders cycles" | |
230 | + orders_cycle_cycle: "Orders' cycle: %{cycle}" | |
231 | + other_open_cycles_lis: "Other open cycles: %{list}. See also %{all}" | |
232 | + see_also_all: "See also %{all}" | |
233 | + _view_products: | |
234 | + the_products: "The products" | |
235 | + add_products: | |
236 | + add_all_missing_produ: "add all missing products %{terms.profile.to_article.singular}" | |
237 | + add_product_to_cycle_: "Add product to cycle's products" | |
238 | + cancel: cancel | |
239 | + close: close | |
240 | + or: or | |
241 | + search_for_a_product_: "Search for a product in our products" | |
242 | + send: Send | |
243 | + type_in_a_name: "Type in a name" | |
244 | + you_already_have_all_: "You already have all your distributed products added" | |
245 | + index: | |
246 | + and_are_from_the_mont: "and are from the month of" | |
247 | + closed_cycles: "Closed Cycles" | |
248 | + filter: Filter | |
249 | + new_cycle: "New cycle" | |
250 | + no_cycles_to_show: "No cycles to show" | |
251 | + open_cycles: "Open Cycles" | |
252 | + orders_cycles: "Orders' Cycles" | |
253 | + show_cycles_from_year: "Show cycles from year" | |
254 | + | |
255 | +en_US: | |
256 | + <<: *en-US | |
257 | +en: | |
258 | + <<: *en-US | |
259 | + | ... | ... |
... | ... | @@ -0,0 +1,257 @@ |
1 | +pt-BR: &pt-BR | |
2 | + | |
3 | + orders_cycle_plugin: | |
4 | + lib: | |
5 | + plugin: | |
6 | + name: "Ciclo de pedidos" | |
7 | + description: "Criar e administrar ciclos de pedidos" | |
8 | + ext: | |
9 | + orders_plugin: | |
10 | + order: | |
11 | + cyclecode_ordercode: "%{cyclecode}.%{ordercode}" | |
12 | + mailer: | |
13 | + order_was_changed: "[%{profile}] Seu pedido foi modificado" | |
14 | + order_block: | |
15 | + distribution_orders_c: "Ciclos de pedidos para os(as) consumidores(as)" | |
16 | + offer_cycles_for_you_: "Ciclo de oferta para os(as) consumidores(as) fazerem pedidos" | |
17 | + orders_cycles: "Ciclos de pedidos" | |
18 | + controllers: | |
19 | + myprofile: | |
20 | + message_controller: | |
21 | + message_sent: "A mensagem foi enviada" | |
22 | + product_controller: | |
23 | + product_removed_from_: "Produto removido do ciclo" | |
24 | + product_removed_succe: "Produto removido com sucesso" | |
25 | + the_product_was_not_r: "O produto não foi removido" | |
26 | + cycle_controller: | |
27 | + cycle_created: "Ciclo criado" | |
28 | + cycle_n_n: "Ciclo n.%{n}" | |
29 | + new_open_cycle: "Novo ciclo aberto" | |
30 | + | |
31 | + models: | |
32 | + cycle: | |
33 | + code_name: "%{code}. %{name}" | |
34 | + delivery_period_befor: "Período de entrega antes do período de pedidos" | |
35 | + invalid_delivery_peri: "Período de entrega inválido" | |
36 | + invalid_orders_period: "Período de pedidos inválido" | |
37 | + statuses: | |
38 | + edition: Edição | |
39 | + orders: Pedidos | |
40 | + purchases: Compras | |
41 | + receipts: Recebimentos | |
42 | + separation: Separação | |
43 | + delivery: Entrega | |
44 | + closing: Fechamento | |
45 | + views: | |
46 | + gadgets: | |
47 | + _cycle: | |
48 | + happening: Acontecendo | |
49 | + orders_open_b_cycle: "Pedidos abertos: <b>%{cycle}</b>" | |
50 | + place_an_order: "place an order" | |
51 | + see_orders_cycle: "Ver ciclo de pedidos" | |
52 | + cycles: | |
53 | + all_cycles: "todos ciclos" | |
54 | + mailer: | |
55 | + open_cycle: | |
56 | + a_new_cycle_is_open_c: "Um novo ciclo de pedidos está aberto chamado " | |
57 | + hello_member_of_name: "Olá membros da comunidade %{name}!" | |
58 | + the_administrator_let: "A/O administrador(a) deixou uma mensagem sobre este ciclo" | |
59 | + the_cycle_description: "A descrição do ciclo é.." | |
60 | + order: | |
61 | + _consumer_orders: | |
62 | + caution: "<strong>Cuidado</strong>, voce está editando os pedidos de \"%{consumer}\". É preferível fazer pequenas edições pela administração do ciclo. Desta forma, a pessoa será propriamente avisada das mudanças. Nós recomendamos que esta página seja usada somente se você está fazendo o pedido para outra pessoa." | |
63 | + show_cancelled_orders: "mostrar pedidos cancelados" | |
64 | + hide_cancelled_orders: "esconder pedidos cancelados" | |
65 | + administration_of_thi: "Administração deste ciclo" | |
66 | + before_the_closing: "(antes do fechamento)" | |
67 | + change_order: "Reabrir o pedido" | |
68 | + edit_your_orders: "Edite seus pedidos" | |
69 | + login: login | |
70 | + new_order: "Novo pedido" | |
71 | + repeat_order: "Repetir pedido" | |
72 | + orders_from_another_m: "Orders from another member" | |
73 | + orders_from_consumer_: "Pedidos de \"%{consumer}\" neste ciclo" | |
74 | + send_message_to_the_m: "Enviar mensagem para gestores" | |
75 | + sign_up: registre-se | |
76 | + this_cycle_is_already: "Este ciclo já foi fechado." | |
77 | + this_cycle_is_not_ope: "Este ciclo ainda não está aberto." | |
78 | + the_time_for_orders_is: "O período de pedidos para esse ciclo é de %{start} até %{finish}" | |
79 | + to_place_an_order_you: "Para fazer um pedido você precisa estar logado e registrado %{terms.profile.at_article.singular}. Por favor faça %{login} ou %{signup}." | |
80 | + you_haven_t_placed_an: "Você ainda não fez pedidos neste ciclo." | |
81 | + you_still_can: "Você ainda pode:" | |
82 | + your_order_is_confirm: "Seu pedido está confirmado e registrado. Por favor, siga as diretrizes do método de entrega abaixo para que isso aconteça sem problemas." | |
83 | + your_order_was_cancel: "Seu pedido foi cancelado" | |
84 | + your_order_wasn_t_con: "Seu pedido não foi confirmado e o período de pedidos terminou." | |
85 | + your_orders_on_this_c: "Seus pedidos neste ciclo" | |
86 | + associate_to_order: "Associe-se para realizar pedidos" | |
87 | + _filter_products: | |
88 | + active: Ativo | |
89 | + all_the_categories: "todas as categorias" | |
90 | + all_the_suppliers: "todos %{terms.supplier.article.plural}" | |
91 | + and_being: "e que estejam" | |
92 | + anyone: anyone | |
93 | + bigger_than_the_stock: "maior do que o estoque" | |
94 | + filter: Filtro | |
95 | + in_any_state: "Em qualquer estado" | |
96 | + inactive: Inativo | |
97 | + product_name: "Nome do produto" | |
98 | + supplier: "%{terms.supplier.singular.capitalize}" | |
99 | + whose_qty_available_i: "cuja quantidade disponível é" | |
100 | + _status: | |
101 | + code_status_message: "%{code} %{status_message}" | |
102 | + open_it: abrir | |
103 | + index: | |
104 | + code: "%{code}." | |
105 | + orders_cycles: "Ciclos de pedidos" | |
106 | + place_an_order: "Faça um pedido" | |
107 | + place_another_order: "Faça um outro pedido" | |
108 | + there_s_no_open_sessi: "Nã há ciclos abertos" | |
109 | + your_orders: "Seus pedidos:" | |
110 | + product: | |
111 | + _order_edit: | |
112 | + add: Adicionar | |
113 | + cancel: Cancelar | |
114 | + change: Mudar | |
115 | + city: Cidade | |
116 | + city_state: "%{city}/%{state}" | |
117 | + include: Incluir | |
118 | + more_about_the_produc: "Mais sobre o produtor \"%{supplier}\"" | |
119 | + no_description: "Sem Descrição" | |
120 | + opening_new_order_for: "Abrindo novo pedido para a inclusão do produto." | |
121 | + opening_order_code_fo: "Abrindo pedido %{code} para a inclusão do produto" | |
122 | + price_percent_price_w: "%{price} + %{percent}% = %{price_with_margin}" | |
123 | + price_s_descriptive: "descrictivo do preço" | |
124 | + product_image: "Imagem do produto" | |
125 | + _order_search: | |
126 | + order_qty: "Qtd pedida" | |
127 | + category: Categoria | |
128 | + producer: Produtor | |
129 | + price: Preço | |
130 | + product: Produto | |
131 | + this_search_hasn_t_re: "Esta busca não retornou produtos" | |
132 | + _cycle_edit: | |
133 | + all_ordered_products: "Todos pedidos deste produto serão removidos também; você deveria primeiro avisar os(as) consumidores(as) que pediram esse produto." | |
134 | + buy_price: "Preço de compra" | |
135 | + buy_unit: "Unidade de compra" | |
136 | + cancel_updates: "Cancelar atualizações" | |
137 | + default_margin: "Margem padrão" | |
138 | + default_sell_price: "Preço de venda padrão" | |
139 | + edit_product: "Editar produto" | |
140 | + margin: Margem | |
141 | + qty_in_stock: "Qtd em estoque" | |
142 | + qty_offered: "Qtd oferecida" | |
143 | + remove_from_cycle: "Remover do ciclo" | |
144 | + save: Salvar | |
145 | + sell_price: "Preço de venda:" | |
146 | + sell_unit: "Unidade de venda" | |
147 | + cycle: | |
148 | + _brief: | |
149 | + confirmed_orders: | |
150 | + zero: "(nenhum pedido confirmado)" | |
151 | + one: "(1 pedido confirmado)" | |
152 | + other: "(%{count} pedidos confirmados)" | |
153 | + code: "%{code}." | |
154 | + delivery: Entrega | |
155 | + orders: Pedidos | |
156 | + _closed: | |
157 | + cycle_already_finishe: "Ciclo já fechado" | |
158 | + _edit_fields: | |
159 | + add_method: "Adicionar método" | |
160 | + add_all_methods: "(adicionar todos)" | |
161 | + available_delivery_me: "Métodos de entrega disponíveis" | |
162 | + cancel_changes: "cancelar alterações" | |
163 | + remove: "remover" | |
164 | + confirm_remove: "Tem certeza de que quer remover este ciclo?" | |
165 | + create_new_cycle: "Criar novo ciclo de pedidos" | |
166 | + deliveries_interval: "Intervalo das Entregas" | |
167 | + description: Descrição | |
168 | + general_settings: "Configurações gerais" | |
169 | + name: Nome | |
170 | + notify_members_of_ope: "Avisar os(as) consumidores(as) da abertura de pedidos" | |
171 | + opening_message: "Mensagem de abertura" | |
172 | + orders_interval: "Intervalo dos Pedidos" | |
173 | + save: Salvar | |
174 | + save_and_open_orders: Salvar e abrir pedidos | |
175 | + create_and_open_orders: Criar e abrir pedidos | |
176 | + this_message_will_be_: "Esta mensagem será mandada por email aos(às) consumidores(as) %{terms.profile.from_article.singular}" | |
177 | + _edit_popin: | |
178 | + close: Fechar | |
179 | + cycle_editing: "Edição de ciclo" | |
180 | + cycle_saved: "Ciclo salvo" | |
181 | + _edition: | |
182 | + info: "O tempo de edição deste ciclo acabou e ele ainda está público.<br/><br/> Ainda é possível editar alguns parametros do ciclo através desta página, no entanto, esteja ciente do risco. Algumas operações têm diferentes implicações dependendo da fase em que se está. Quando assim for, você será avisado por uma janelinha de aviso das consequências das mudanças efetuadas." | |
183 | + add_product: "Adicionar produto" | |
184 | + it_was_automatically_: "Ela foi automaticamente gerada a partir dos produtos ativos e suas respectivas margens. Verifique a lista de produtos e edite-a conforme as necessidades e particularidades deste ciclo de pedidos." | |
185 | + the_following_list_of: "A seguinte lista de produtos está disponível neste ciclo." | |
186 | + the_products: "Os produtos" | |
187 | + _products_loading: "Os produtos estão sendo carregados no ciclo." | |
188 | + _orders: | |
189 | + header_help: "Nesta etapa são recebidos os pedidos %{terms.consumer.from_article.plural}, e é possível supervisioná-los se por acaso existe algum erro mais grave." | |
190 | + the_orders_period_is_: "O período de pedidos está ainda aberto, tome cuidado ao editar os pedidos abertos. Isso pode confundir os usuários." | |
191 | + already_closed: "O período de pedidos já foi fechado, Não é possível editar os pedidos originais. Na fase de redistribuição é possível editar o pedido, e também antes da entrega." | |
192 | + _purchases: | |
193 | + header_help: "Nesta etapa, com base nos pedidos recebidos, são feitas as compras de cada um %{terms.supplier.of_article.plural} para suprir a demanda de todos os pedidos." | |
194 | + _receipts: | |
195 | + header_help: "Nesta etapa são registradas os recebimentos das compras e são editadas quaisquer discrepâncias que possam existir." | |
196 | + _separation: | |
197 | + header_help: "Nesta etapa cada pedido é separado de acordo com a disponibilidade dos produtos encomendados que chegaram." | |
198 | + _delivery: | |
199 | + header_help: "Nesta etapa são registradas as entregas %{terms.consumer.to_article.plural}. Este é o momento de registrar as mudanças em relação ao que foi separado." | |
200 | + _product_lines: | |
201 | + category: Categoria | |
202 | + price: Preço | |
203 | + product: Produto | |
204 | + qty_avail: "Qtd. dispon." | |
205 | + showing_pcount_produc: "Mostrando %{pcount} produtos de %{allpcount}" | |
206 | + supplier: "%{terms.supplier.singular.capitalize}" | |
207 | + _results: | |
208 | + no_cycles_to_show: "Sem ciclos a mostrar" | |
209 | + _timeline: | |
210 | + are_you_sure_you_want_to_reopen: "Tem certeza de que deseja reabrir o ciclo de pedidos?" | |
211 | + are_you_sure_you_want_to_close: "Tem certeza de que deseja encerrar a etapa %{status}?" | |
212 | + call: Call | |
213 | + close: Fechar | |
214 | + close_status: "Encerrar %{status}" | |
215 | + finish_cycle_editing: "Abrir pedidos do ciclo" | |
216 | + reopen_orders_period: "Reabrir ciclo de pedidos" | |
217 | + _title: | |
218 | + new_cycle: "Novo ciclo" | |
219 | + order_cycle: "Ciclo de pedidos: " | |
220 | + _view_dates: | |
221 | + delivery: "Entrega: " | |
222 | + happening: Acontecendo | |
223 | + orders: "Pedidos: " | |
224 | + _view_header: | |
225 | + ? ", " | |
226 | + : ", " | |
227 | + all_orders_cycles: "Todos ciclos abertos" | |
228 | + orders_cycle_cycle: "Ciclo de pedidos: %{cycle}" | |
229 | + other_open_cycles_lis: "Outros ciclos abertos: %{list}. Veja também %{all}" | |
230 | + see_also_all: "Veja também %{all}" | |
231 | + _view_products: | |
232 | + the_products: "Os produtos" | |
233 | + add_products: | |
234 | + add_all_missing_produ: "adicionar todos produtos que faltam %{terms.profile.to_article.singular}" | |
235 | + add_product_to_cycle_: "Adicionar produto à lista de produtos distribuídos" | |
236 | + cancel: Cancelar | |
237 | + close: Fechar | |
238 | + or: ou | |
239 | + search_for_a_product_: "Busca por um produto em nossos produtos" | |
240 | + send: Enviar | |
241 | + type_in_a_name: "Escreva um nome" | |
242 | + you_already_have_all_: "Todos seus produtos distribuídos já foram adicionados" | |
243 | + index: | |
244 | + and_are_from_the_mont: "e que sejam do mês de" | |
245 | + closed_cycles: "Ciclos de pedidos fechados" | |
246 | + filter: Filtro | |
247 | + new_cycle: "Novo ciclo" | |
248 | + no_cycles_to_show: "Sem ciclos a mostrar" | |
249 | + open_cycles: "Ciclos de pedidos Abertos" | |
250 | + orders_cycles: "Ciclo de pedidos" | |
251 | + show_cycles_from_year: "Mostre os ciclos do ano" | |
252 | + | |
253 | +pt_BR: | |
254 | + <<: *pt-BR | |
255 | +pt: | |
256 | + <<: *pt-BR | |
257 | + | ... | ... |
plugins/orders_cycle/models/orders_cycle_plugin/cycle.rb
0 → 100644
... | ... | @@ -0,0 +1,320 @@ |
1 | +class OrdersCyclePlugin::Cycle < ActiveRecord::Base | |
2 | + | |
3 | + attr_accessible :profile, :status, :name, :description, :opening_message | |
4 | + | |
5 | + attr_accessible :start, :finish, :delivery_start, :delivery_finish | |
6 | + attr_accessible :start_date, :start_time, :finish_date, :finish_time, :delivery_start_date, :delivery_start_time, :delivery_finish_date, :delivery_finish_time, | |
7 | + | |
8 | + Statuses = %w[edition orders purchases receipts separation delivery closing] | |
9 | + DbStatuses = %w[new] + Statuses | |
10 | + UserStatuses = Statuses | |
11 | + | |
12 | + # which status the sales are on each cycle status | |
13 | + SaleStatusMap = { | |
14 | + 'edition' => nil, | |
15 | + 'orders' => :ordered, | |
16 | + 'purchases' => :accepted, | |
17 | + 'receipts' => :accepted, | |
18 | + 'separation' => :accepted, | |
19 | + 'delivery' => :separated, | |
20 | + 'closing' => :delivered, | |
21 | + } | |
22 | + # which status the purchases are on each cycle status | |
23 | + PurchaseStatusMap = { | |
24 | + 'edition' => nil, | |
25 | + 'orders' => nil, | |
26 | + 'purchases' => :draft, | |
27 | + 'receipts' => :ordered, | |
28 | + 'separation' => :received, | |
29 | + 'delivery' => :received, | |
30 | + 'closing' => :received, | |
31 | + } | |
32 | + | |
33 | + belongs_to :profile | |
34 | + | |
35 | + has_many :delivery_options, class_name: 'DeliveryPlugin::Option', dependent: :destroy, | |
36 | + as: :owner, conditions: ["delivery_plugin_options.owner_type = 'OrdersCyclePlugin::Cycle'"] | |
37 | + has_many :delivery_methods, through: :delivery_options, source: :delivery_method | |
38 | + | |
39 | + has_many :cycle_orders, class_name: 'OrdersCyclePlugin::CycleOrder', foreign_key: :cycle_id, dependent: :destroy, order: 'id ASC' | |
40 | + | |
41 | + # cannot use :order because of months/years named_scope | |
42 | + has_many :sales, through: :cycle_orders, source: :sale | |
43 | + has_many :purchases, through: :cycle_orders, source: :purchase | |
44 | + | |
45 | + has_many :cycle_products, foreign_key: :cycle_id, class_name: 'OrdersCyclePlugin::CycleProduct', dependent: :destroy | |
46 | + has_many :products, through: :cycle_products, source: :product, order: 'products.name ASC', | |
47 | + include: [ :from_2x_products, :from_products, {profile: :domains}, ] | |
48 | + | |
49 | + has_many :consumers, through: :sales, source: :consumer, order: 'name ASC', uniq: true | |
50 | + has_many :suppliers, through: :products, source: :suppliers, order: 'suppliers_plugin_suppliers.name ASC', uniq: true | |
51 | + has_many :orders_suppliers, through: :sales, source: :profile, order: 'name ASC' | |
52 | + | |
53 | + has_many :from_products, through: :products, order: 'name ASC', uniq: true | |
54 | + has_many :supplier_products, through: :products, order: 'name ASC', uniq: true | |
55 | + has_many :product_categories, through: :products, order: 'name ASC', uniq: true | |
56 | + | |
57 | + has_many :orders_confirmed, through: :cycle_orders, source: :sale, order: 'id ASC', | |
58 | + conditions: ['orders_plugin_orders.ordered_at IS NOT NULL'] | |
59 | + | |
60 | + has_many :items_selled, through: :sales, source: :items | |
61 | + has_many :items_purchased, through: :purchases, source: :items | |
62 | + # DEPRECATED | |
63 | + has_many :items, through: :orders_confirmed | |
64 | + | |
65 | + has_many :ordered_suppliers, through: :orders_confirmed, source: :suppliers | |
66 | + | |
67 | + has_many :ordered_offered_products, through: :orders_confirmed, source: :offered_products, uniq: true, include: [:suppliers] | |
68 | + has_many :ordered_distributed_products, through: :orders_confirmed, source: :distributed_products, uniq: true, include: [:suppliers] | |
69 | + has_many :ordered_supplier_products, through: :orders_confirmed, source: :supplier_products, uniq: true, include: [:suppliers] | |
70 | + | |
71 | + has_many :volunteers_periods, class_name: 'VolunteersPlugin::Period', as: :owner | |
72 | + has_many :volunteers, through: :volunteers_periods, source: :profile | |
73 | + attr_accessible :volunteers_periods_attributes | |
74 | + accepts_nested_attributes_for :volunteers_periods, allow_destroy: true | |
75 | + | |
76 | + scope :has_volunteers_periods, -> {uniq.joins [:volunteers_periods]} | |
77 | + | |
78 | + # status scopes | |
79 | + scope :on_edition, -> { where status: 'edition' } | |
80 | + scope :on_orders, -> { where status: 'orders' } | |
81 | + scope :on_purchases, -> { where status: 'purchases' } | |
82 | + scope :on_separation, -> { where status: 'separation' } | |
83 | + scope :on_delivery, -> { where status: 'delivery' } | |
84 | + scope :on_closing, -> { where status: 'closing' } | |
85 | + | |
86 | + scope :defuncts, conditions: ["status = 'new' AND created_at < ?", 2.days.ago] | |
87 | + scope :not_new, conditions: ["status <> 'new'"] | |
88 | + scope :on_orders, lambda { | |
89 | + {conditions: ["status = 'orders' AND ( (start <= :now AND finish IS NULL) OR (start <= :now AND finish >= :now) )", | |
90 | + {now: DateTime.now}]} | |
91 | + } | |
92 | + scope :not_on_orders, lambda { | |
93 | + {conditions: ["NOT (status = 'orders' AND ( (start <= :now AND finish IS NULL) OR (start <= :now AND finish >= :now) ) )", | |
94 | + {now: DateTime.now}]} | |
95 | + } | |
96 | + scope :opened, conditions: ["status <> 'new' AND status <> 'closing'"] | |
97 | + scope :closing, conditions: ["status = 'closing'"] | |
98 | + scope :by_status, lambda { |status| { conditions: {status: status} } } | |
99 | + | |
100 | + scope :months, select: 'DISTINCT(EXTRACT(months FROM start)) as month', order: 'month DESC' | |
101 | + scope :years, select: 'DISTINCT(EXTRACT(YEAR FROM start)) as year', order: 'year DESC' | |
102 | + | |
103 | + scope :by_month, lambda { |month| { | |
104 | + conditions: [ 'EXTRACT(month FROM start) <= :month AND EXTRACT(month FROM finish) >= :month', { month: month } ]} | |
105 | + } | |
106 | + scope :by_year, lambda { |year| { | |
107 | + conditions: [ 'EXTRACT(year FROM start) <= :year AND EXTRACT(year FROM finish) >= :year', { year: year } ]} | |
108 | + } | |
109 | + scope :by_range, lambda { |range| { | |
110 | + conditions: [ 'start BETWEEN :start AND :finish OR finish BETWEEN :start AND :finish', | |
111 | + { start: range.first, finish: range.last } | |
112 | + ]} | |
113 | + } | |
114 | + | |
115 | + validates_presence_of :profile | |
116 | + validates_presence_of :name, if: :not_new? | |
117 | + validates_presence_of :start, if: :not_new? | |
118 | + # FIXME: The user frequenqly forget about this, and this will crash the app in some places, so don't enable this | |
119 | + #validates_presence_of :delivery_options, unless: :new_or_edition? | |
120 | + validates_inclusion_of :status, in: DbStatuses, if: :not_new? | |
121 | + validates_numericality_of :margin_percentage, allow_nil: true, if: :not_new? | |
122 | + validate :validate_orders_dates, if: :not_new? | |
123 | + validate :validate_delivery_dates, if: :not_new? | |
124 | + | |
125 | + before_validation :step_new | |
126 | + before_validation :update_orders_status | |
127 | + before_save :add_products_on_edition_state | |
128 | + after_create :delay_purge_profile_defuncts | |
129 | + | |
130 | + extend CodeNumbering::ClassMethods | |
131 | + code_numbering :code, scope: Proc.new { self.profile.orders_cycles } | |
132 | + | |
133 | + extend OrdersPlugin::DateRangeAttr::ClassMethods | |
134 | + date_range_attr :start, :finish | |
135 | + date_range_attr :delivery_start, :delivery_finish | |
136 | + | |
137 | + extend SplitDatetime::SplitMethods | |
138 | + split_datetime :start | |
139 | + split_datetime :finish | |
140 | + split_datetime :delivery_start | |
141 | + split_datetime :delivery_finish | |
142 | + | |
143 | + serialize :data, Hash | |
144 | + | |
145 | + def name_with_code | |
146 | + I18n.t('orders_cycle_plugin.models.cycle.code_name') % { | |
147 | + code: code, name: name | |
148 | + } | |
149 | + end | |
150 | + def total_price_consumer_ordered | |
151 | + self.items.sum :price_consumer_ordered | |
152 | + end | |
153 | + | |
154 | + def status | |
155 | + self['status'] = 'closing' if self['status'] == 'closed' | |
156 | + self['status'] | |
157 | + end | |
158 | + | |
159 | + def step | |
160 | + self.status = DbStatuses[DbStatuses.index(self.status)+1] | |
161 | + end | |
162 | + def step_back | |
163 | + self.status = DbStatuses[DbStatuses.index(self.status)-1] | |
164 | + end | |
165 | + | |
166 | + def passed_by? status | |
167 | + DbStatuses.index(self.status) > DbStatuses.index(status) rescue false | |
168 | + end | |
169 | + | |
170 | + def new? | |
171 | + self.status == 'new' | |
172 | + end | |
173 | + def not_new? | |
174 | + self.status != 'new' | |
175 | + end | |
176 | + def open? | |
177 | + !self.closing? | |
178 | + end | |
179 | + def closing? | |
180 | + self.status == 'closing' | |
181 | + end | |
182 | + def edition? | |
183 | + self.status == 'edition' | |
184 | + end | |
185 | + def new_or_edition? | |
186 | + self.status == 'new' or self.status == 'edition' | |
187 | + end | |
188 | + def after_orders? | |
189 | + now = DateTime.now | |
190 | + status == 'orders' && self.finish < now | |
191 | + end | |
192 | + def before_orders? | |
193 | + now = DateTime.now | |
194 | + status == 'orders' && self.start >= now | |
195 | + end | |
196 | + def orders? | |
197 | + now = DateTime.now | |
198 | + status == 'orders' && ( (self.start <= now && self.finish.nil?) || (self.start <= now && self.finish >= now) ) | |
199 | + end | |
200 | + def delivery? | |
201 | + now = DateTime.now | |
202 | + status == 'delivery' && ( (self.delivery_start <= now && self.delivery_finish.nil?) || (self.delivery_start <= now && self.delivery_finish >= now) ) | |
203 | + end | |
204 | + | |
205 | + def may_order? consumer | |
206 | + self.orders? and consumer.present? and consumer.in? profile.members | |
207 | + end | |
208 | + | |
209 | + def consumer_previous_orders consumer | |
210 | + self.profile.orders_cycles_sales.where(consumer_id: consumer.id). | |
211 | + where('orders_cycle_plugin_cycle_orders.cycle_id <> ?', self.id) | |
212 | + end | |
213 | + | |
214 | + def products_for_order | |
215 | + # FIXME name alias conflict | |
216 | + #self.products.unarchived.with_price.order('products.name ASC') | |
217 | + self.products.unarchived.with_price | |
218 | + end | |
219 | + | |
220 | + def supplier_products_by_suppliers orders = self.sales.ordered | |
221 | + OrdersCyclePlugin::Order.supplier_products_by_suppliers orders | |
222 | + end | |
223 | + | |
224 | + def generate_purchases sales = self.sales.ordered | |
225 | + return self.purchases if self.purchases.present? | |
226 | + | |
227 | + sales.each do |sale| | |
228 | + sale.add_purchases_items_without_delay | |
229 | + end | |
230 | + | |
231 | + self.purchases true | |
232 | + end | |
233 | + def regenerate_purchases sales = self.sales.ordered | |
234 | + self.purchases.destroy_all | |
235 | + self.generate_purchases sales | |
236 | + end | |
237 | + | |
238 | + def add_products | |
239 | + return if self.products.count > 0 | |
240 | + ActiveRecord::Base.transaction do | |
241 | + self.profile.products.supplied.unarchived.available.find_each batch_size: 20 do |product| | |
242 | + self.add_product product | |
243 | + end | |
244 | + end | |
245 | + end | |
246 | + | |
247 | + def add_product product | |
248 | + OrdersCyclePlugin::OfferedProduct.create_from product, self | |
249 | + end | |
250 | + | |
251 | + def add_products_job | |
252 | + @add_products_job ||= Delayed::Job.find_by_id self.data[:add_products_job_id] | |
253 | + end | |
254 | + | |
255 | + protected | |
256 | + | |
257 | + def add_products_on_edition_state | |
258 | + return unless self.status_was == 'new' | |
259 | + job = self.delay.add_products | |
260 | + self.data[:add_products_job_id] = job.id | |
261 | + end | |
262 | + | |
263 | + def step_new | |
264 | + return if new_record? | |
265 | + self.step if self.new? | |
266 | + end | |
267 | + | |
268 | + def update_sales_status from, to | |
269 | + sales = self.sales.where(status: from.to_s) | |
270 | + sales.each do |sale| | |
271 | + sale.update_attributes status: to.to_s | |
272 | + end | |
273 | + end | |
274 | + | |
275 | + def update_purchases_status from, to | |
276 | + purchases = self.purchases.where(status: from.to_s) | |
277 | + purchases.each do |purchase| | |
278 | + purchase.update_attributes status: to.to_s | |
279 | + end | |
280 | + end | |
281 | + | |
282 | + def update_orders_status | |
283 | + # step orders to next_status on status change | |
284 | + return if self.new? or self.status_was == "new" or self.status_was == self.status | |
285 | + | |
286 | + # Don't rewind confirmed sales | |
287 | + unless self.status_was == 'orders' and self.status == 'edition' | |
288 | + sale_status_was = SaleStatusMap[self.status_was] | |
289 | + new_sale_status = SaleStatusMap[self.status] | |
290 | + self.delay.update_sales_status sale_status_was, new_sale_status unless sale_status_was == new_sale_status | |
291 | + end | |
292 | + | |
293 | + # Don't rewind confirmed purchases | |
294 | + unless self.status_was == 'receipts' and self.status == 'purchases' | |
295 | + purchase_status_was = PurchaseStatusMap[self.status_was] | |
296 | + new_purchase_status = PurchaseStatusMap[self.status] | |
297 | + self.delay.update_purchases_status purchase_status_was, new_purchase_status unless purchase_status_was == new_purchase_status | |
298 | + end | |
299 | + end | |
300 | + | |
301 | + def validate_orders_dates | |
302 | + return if self.new? or self.finish.nil? | |
303 | + errors.add :base, (I18n.t('orders_cycle_plugin.models.cycle.invalid_orders_period')) unless self.start < self.finish | |
304 | + end | |
305 | + | |
306 | + def validate_delivery_dates | |
307 | + return if self.new? or delivery_start.nil? or delivery_finish.nil? | |
308 | + errors.add :base, I18n.t('orders_cycle_plugin.models.cycle.invalid_delivery_peri') unless delivery_start < delivery_finish | |
309 | + errors.add :base, I18n.t('orders_cycle_plugin.models.cycle.delivery_period_befor') unless finish <= delivery_start | |
310 | + end | |
311 | + | |
312 | + def purge_profile_defuncts | |
313 | + self.class.where(profile_id: self.profile_id).defuncts.destroy_all | |
314 | + end | |
315 | + | |
316 | + def delay_purge_profile_defuncts | |
317 | + self.delay.purge_profile_defuncts | |
318 | + end | |
319 | + | |
320 | +end | ... | ... |
plugins/orders_cycle/models/orders_cycle_plugin/cycle_order.rb
0 → 100644
... | ... | @@ -0,0 +1,16 @@ |
1 | +class OrdersCyclePlugin::CycleOrder < ActiveRecord::Base | |
2 | + | |
3 | + belongs_to :cycle, class_name: 'OrdersCyclePlugin::Cycle' | |
4 | + belongs_to :sale, class_name: 'OrdersCyclePlugin::Sale', foreign_key: :sale_id, dependent: :destroy | |
5 | + belongs_to :purchase, class_name: 'OrdersCyclePlugin::Purchase', foreign_key: :purchase_id, dependent: :destroy | |
6 | + | |
7 | + validates_presence_of :cycle | |
8 | + validate :sale_or_purchase | |
9 | + | |
10 | + protected | |
11 | + | |
12 | + def sale_or_purchase | |
13 | + errors.add :base, "Specify a sale of purchase" unless self.sale_id or self.purchase_id | |
14 | + end | |
15 | + | |
16 | +end | ... | ... |
plugins/orders_cycle/models/orders_cycle_plugin/cycle_product.rb
0 → 100644
... | ... | @@ -0,0 +1,11 @@ |
1 | +class OrdersCyclePlugin::CycleProduct < ActiveRecord::Base | |
2 | + | |
3 | + self.table_name = :orders_cycle_plugin_cycle_products | |
4 | + | |
5 | + belongs_to :cycle, :class_name => 'OrdersCyclePlugin::Cycle' | |
6 | + belongs_to :product, :class_name => 'OrdersCyclePlugin::OfferedProduct', :dependent => :destroy # a product only belongs to one cycle | |
7 | + | |
8 | + validates_presence_of :cycle | |
9 | + validates_presence_of :product | |
10 | + | |
11 | +end | ... | ... |
... | ... | @@ -0,0 +1,44 @@ |
1 | +class OrdersCyclePlugin::Item < OrdersPlugin::Item | |
2 | + | |
3 | + has_one :supplier, through: :product | |
4 | + | |
5 | + # see also: repeat_product | |
6 | + attr_accessor :repeat_cycle | |
7 | + | |
8 | + delegate :cycle, to: :order | |
9 | + | |
10 | + # OVERRIDE OrdersPlugin::Item | |
11 | + belongs_to :order, class_name: '::OrdersCyclePlugin::Order', foreign_key: :order_id, touch: true | |
12 | + belongs_to :sale, class_name: '::OrdersCyclePlugin::Sale', foreign_key: :order_id, touch: true | |
13 | + belongs_to :purchase, class_name: '::OrdersCyclePlugin::Purchase', foreign_key: :order_id, touch: true | |
14 | + | |
15 | + # WORKAROUND for direct relationship | |
16 | + belongs_to :offered_product, foreign_key: :product_id, class_name: 'OrdersCyclePlugin::OfferedProduct' | |
17 | + has_many :from_products, through: :offered_product | |
18 | + has_one :from_product, through: :offered_product | |
19 | + has_many :to_products, through: :offered_product | |
20 | + has_one :to_product, through: :offered_product | |
21 | + has_many :sources_supplier_products, through: :offered_product | |
22 | + has_one :sources_supplier_product, through: :offered_product | |
23 | + has_many :supplier_products, through: :offered_product | |
24 | + has_one :supplier_product, through: :offered_product | |
25 | + has_many :suppliers, through: :offered_product | |
26 | + has_one :supplier, through: :offered_product | |
27 | + | |
28 | + # what items were selled from this item | |
29 | + def selled_items | |
30 | + self.order.cycle.selled_items.where(profile_id: self.consumer.id, orders_plugin_item: {product_id: self.product_id}) | |
31 | + end | |
32 | + # what items were purchased from this item | |
33 | + def purchased_items | |
34 | + self.order.cycle.purchases.where(consumer_id: self.profile.id) | |
35 | + end | |
36 | + | |
37 | + # override | |
38 | + def repeat_product | |
39 | + distributed_product = self.from_product | |
40 | + return unless self.repeat_cycle and distributed_product | |
41 | + self.repeat_cycle.products.where(from_products_products: {id: distributed_product.id}).first | |
42 | + end | |
43 | + | |
44 | +end | ... | ... |
plugins/orders_cycle/models/orders_cycle_plugin/offered_product.rb
0 → 100644
... | ... | @@ -0,0 +1,108 @@ |
1 | +class OrdersCyclePlugin::OfferedProduct < SuppliersPlugin::BaseProduct | |
2 | + | |
3 | + # FIXME: WORKAROUND for https://github.com/rails/rails/issues/6663 | |
4 | + # OrdersCyclePlugin::Sale.find(3697).cycle.suppliers returns empty without this | |
5 | + def self.finder_needs_type_condition? | |
6 | + false | |
7 | + end | |
8 | + | |
9 | + has_many :cycle_products, foreign_key: :product_id, class_name: 'OrdersCyclePlugin::CycleProduct' | |
10 | + has_one :cycle_product, foreign_key: :product_id, class_name: 'OrdersCyclePlugin::CycleProduct' | |
11 | + has_many :cycles, through: :cycle_products | |
12 | + has_one :cycle, through: :cycle_product | |
13 | + | |
14 | + # OVERRIDE suppliers/lib/ext/product.rb | |
15 | + # for products in cycle, these are the products of the suppliers: | |
16 | + # p in cycle -> p distributed -> p from supplier | |
17 | + # So, sources_supplier_products is the same as sources_from_2x_products | |
18 | + has_many :sources_supplier_products, through: :from_products, source: :sources_from_products | |
19 | + has_one :sources_supplier_product, through: :from_product, source: :sources_from_product | |
20 | + # necessary only due to the override of sources_supplier_products, as rails somehow caches the old reference | |
21 | + # copied from suppliers/lib/ext/product | |
22 | + has_many :supplier_products, through: :sources_supplier_products, source: :from_product, order: 'id ASC' | |
23 | + has_one :supplier_product, through: :sources_supplier_product, source: :from_product, order: 'id ASC', autosave: true | |
24 | + has_many :suppliers, through: :sources_supplier_products, uniq: true, order: 'id ASC' | |
25 | + has_one :supplier, through: :sources_supplier_product, order: 'id ASC' | |
26 | + | |
27 | + instance_exec &OrdersPlugin::Item::DefineTotals | |
28 | + extend CurrencyHelper::ClassMethods | |
29 | + has_currency :buy_price | |
30 | + | |
31 | + # test this before use! | |
32 | + #validates_presence_of :cycle | |
33 | + | |
34 | + # remove on rails4 | |
35 | + scope :with_price, conditions: 'products.price > 0' | |
36 | + scope :with_product_category_id, lambda { |id| { conditions: {product_category_id: id} } } | |
37 | + def self.search_scope scope, params | |
38 | + scope = scope.from_supplier_id params[:supplier_id] if params[:supplier_id].present? | |
39 | + scope = scope.with_available(if params[:available] == 'true' then true else false end) if params[:available].present? | |
40 | + scope = scope.name_like params[:name] if params[:name].present? | |
41 | + scope = scope.with_product_category_id params[:category_id] if params[:category_id].present? | |
42 | + scope | |
43 | + end | |
44 | + | |
45 | + def self.create_from product, cycle | |
46 | + op = self.new | |
47 | + | |
48 | + product.attributes.except('id').each{ |a,v| op.send "#{a}=", v } | |
49 | + op.freeze_default_attributes product | |
50 | + op.profile = product.profile | |
51 | + op.type = self.name | |
52 | + | |
53 | + op.from_products << product | |
54 | + cycle.products << op if cycle | |
55 | + | |
56 | + op | |
57 | + end | |
58 | + | |
59 | + # always recalculate in case something has changed | |
60 | + def margin_percentage | |
61 | + return self['margin_percentage'] if price.nil? or buy_price.nil? or price.zero? or buy_price.zero? | |
62 | + ((price / buy_price) - 1) * 100 | |
63 | + end | |
64 | + def margin_percentage= value | |
65 | + self['margin_percentage'] = value | |
66 | + self.price = self.price_with_margins buy_price | |
67 | + end | |
68 | + | |
69 | + def sell_unit | |
70 | + self.unit || self.class.default_unit | |
71 | + end | |
72 | + | |
73 | + # reimplement to don't destroy this, keeping history in cycles | |
74 | + # offered products copy attributes | |
75 | + def dependent? | |
76 | + false | |
77 | + end | |
78 | + | |
79 | + # cycle products freezes properties and don't use the original | |
80 | + DEFAULT_ATTRIBUTES.each do |a| | |
81 | + define_method "default_#{a}" do | |
82 | + nil | |
83 | + end | |
84 | + end | |
85 | + | |
86 | + FROOZEN_DEFAULT_ATTRIBUTES = DEFAULT_ATTRIBUTES | |
87 | + def freeze_default_attributes from_product | |
88 | + FROOZEN_DEFAULT_ATTRIBUTES.each do |attr| | |
89 | + self[attr] = from_product.send(attr) if from_product[attr] or from_product.respond_to? attr | |
90 | + end | |
91 | + end | |
92 | + | |
93 | + def solr_index? | |
94 | + false | |
95 | + end | |
96 | + | |
97 | + protected | |
98 | + | |
99 | + after_update :sync_ordered | |
100 | + def sync_ordered | |
101 | + return unless self.price_changed? | |
102 | + self.items.each do |item| | |
103 | + item.calculate_prices self.price | |
104 | + item.save! | |
105 | + end | |
106 | + end | |
107 | + | |
108 | +end | ... | ... |
plugins/orders_cycle/models/orders_cycle_plugin/order.rb
0 → 100644
plugins/orders_cycle/models/orders_cycle_plugin/order_base.rb
0 → 100644
... | ... | @@ -0,0 +1,64 @@ |
1 | +# This module is needed to pretend a multiple inheritance for Sale and Purchase | |
2 | +module OrdersCyclePlugin::OrderBase | |
3 | + | |
4 | + extend ActiveSupport::Concern | |
5 | + included do | |
6 | + | |
7 | + attr_accessible :cycle | |
8 | + | |
9 | + has_many :cycle_sales, class_name: 'OrdersCyclePlugin::CycleOrder', foreign_key: :sale_id, dependent: :destroy | |
10 | + has_one :cycle_sale, class_name: 'OrdersCyclePlugin::CycleOrder', foreign_key: :sale_id | |
11 | + has_many :cycle_purchases, class_name: 'OrdersCyclePlugin::CycleOrder', foreign_key: :purchase_id, dependent: :destroy | |
12 | + has_one :cycle_purchase, class_name: 'OrdersCyclePlugin::CycleOrder', foreign_key: :purchase_id | |
13 | + def all_cycles | |
14 | + self.cycle_sales.includes(:cycle).map(&:cycle) + self.cycle_purchases.includes(:cycle).map(&:cycle) | |
15 | + end | |
16 | + | |
17 | + # TODO: test if the has_one defined on Sale/Purchase works and these are not needed | |
18 | + def cycle | |
19 | + self.cycles.first | |
20 | + end | |
21 | + def cycle= cycle | |
22 | + self.cycles = [cycle] | |
23 | + end | |
24 | + | |
25 | + scope :for_cycle, -> (cycle) { | |
26 | + where('orders_cycle_plugin_cycles.id = ?', cycle.id). | |
27 | + joins(:cycles) | |
28 | + } | |
29 | + | |
30 | + has_many :items, class_name: 'OrdersCyclePlugin::Item', foreign_key: :order_id, dependent: :destroy, order: 'name ASC' | |
31 | + | |
32 | + has_many :offered_products, through: :items, source: :offered_product, uniq: true | |
33 | + has_many :distributed_products, through: :offered_products, source: :from_products, uniq: true | |
34 | + has_many :supplier_products, through: :distributed_products, source: :from_products, uniq: true | |
35 | + | |
36 | + has_many :suppliers, through: :supplier_products, uniq: true | |
37 | + | |
38 | + extend CodeNumbering::ClassMethods | |
39 | + code_numbering :code, scope: (proc do | |
40 | + if self.cycle then self.cycle.send(self.orders_name) else self.profile.orders end | |
41 | + end) | |
42 | + | |
43 | + def code | |
44 | + I18n.t('orders_cycle_plugin.lib.ext.orders_plugin.order.cyclecode_ordercode') % { | |
45 | + cyclecode: self.cycle.code, ordercode: self['code'] | |
46 | + } | |
47 | + end | |
48 | + | |
49 | + def delivery_methods | |
50 | + self.cycle.delivery_methods | |
51 | + end | |
52 | + | |
53 | + def repeat_cycle= cycle | |
54 | + self.items.each{ |i| i.repeat_cycle = cycle } | |
55 | + end | |
56 | + | |
57 | + def available_products | |
58 | + self.cycle.products | |
59 | + end | |
60 | + | |
61 | + protected | |
62 | + end | |
63 | + | |
64 | +end | ... | ... |
plugins/orders_cycle/models/orders_cycle_plugin/purchase.rb
0 → 100644
... | ... | @@ -0,0 +1,80 @@ |
1 | +class OrdersCyclePlugin::Sale < OrdersPlugin::Sale | |
2 | + | |
3 | + include OrdersCyclePlugin::OrderBase | |
4 | + | |
5 | + has_many :cycles, through: :cycle_sales, source: :cycle | |
6 | + has_one :cycle, through: :cycle_sale, source: :cycle | |
7 | + | |
8 | + after_save :change_purchases, if: :cycle | |
9 | + before_destroy :remove_purchases_items, if: :cycle | |
10 | + | |
11 | + def current_status | |
12 | + return 'forgotten' if self.forgotten? | |
13 | + super | |
14 | + end | |
15 | + | |
16 | + def delivery? | |
17 | + self.cycle.delivery? | |
18 | + end | |
19 | + def forgotten? | |
20 | + self.draft? and !self.cycle.orders? | |
21 | + end | |
22 | + | |
23 | + def open? | |
24 | + super and self.cycle.orders? | |
25 | + end | |
26 | + | |
27 | + def supplier_delivery | |
28 | + super || (self.cycle.delivery_methods.first rescue nil) | |
29 | + end | |
30 | + | |
31 | + def change_purchases | |
32 | + return unless self.status_was.present? | |
33 | + if self.ordered_at_was.nil? and self.ordered_at.present? | |
34 | + self.add_purchases_items | |
35 | + elsif self.ordered_at_was.present? and self.ordered_at.nil? | |
36 | + self.remove_purchases_items | |
37 | + end | |
38 | + end | |
39 | + | |
40 | + def add_purchases_items | |
41 | + ActiveRecord::Base.transaction do | |
42 | + self.items.each do |item| | |
43 | + next unless supplier_product = item.product.supplier_product | |
44 | + next unless supplier = supplier_product.profile | |
45 | + | |
46 | + purchase = self.cycle.purchases.for_profile(supplier).first | |
47 | + purchase ||= OrdersCyclePlugin::Purchase.create! cycle: self.cycle, consumer: self.profile, profile: supplier | |
48 | + | |
49 | + purchased_item = purchase.items.for_product(supplier_product).first | |
50 | + purchased_item ||= purchase.items.build purchase: purchase, product: supplier_product | |
51 | + purchased_item.quantity_consumer_ordered ||= 0 | |
52 | + purchased_item.quantity_consumer_ordered += item.status_quantity | |
53 | + purchased_item.price_consumer_ordered ||= 0 | |
54 | + purchased_item.price_consumer_ordered += item.status_quantity * supplier_product.price | |
55 | + purchased_item.save! | |
56 | + end | |
57 | + end | |
58 | + end | |
59 | + | |
60 | + def remove_purchases_items | |
61 | + ActiveRecord::Base.transaction do | |
62 | + self.items.each do |item| | |
63 | + next unless supplier_product = item.product.supplier_product | |
64 | + next unless purchase = supplier_product.orders_cycles_purchases.for_cycle(self.cycle).first | |
65 | + | |
66 | + purchased_item = purchase.items.for_product(supplier_product).first | |
67 | + purchased_item.quantity_consumer_ordered -= item.status_quantity | |
68 | + purchased_item.price_consumer_ordered -= item.status_quantity * supplier_product.price | |
69 | + purchased_item.save! | |
70 | + | |
71 | + purchased_item.destroy if purchased_item.quantity_consumer_ordered.zero? | |
72 | + purchase.destroy if purchase.items(true).blank? | |
73 | + end | |
74 | + end | |
75 | + end | |
76 | + | |
77 | + handle_asynchronously :add_purchases_items | |
78 | + handle_asynchronously :remove_purchases_items | |
79 | + | |
80 | +end | ... | ... |
598 Bytes
320 Bytes
... | ... | @@ -0,0 +1,211 @@ |
1 | + | |
2 | +orders_cycle = { | |
3 | + | |
4 | + cycle: { | |
5 | + | |
6 | + edit: { | |
7 | + openingMessage: { | |
8 | + onKeyup: function(textArea) { | |
9 | + textArea = $(textArea) | |
10 | + var checked = textArea.val() ? true : false; | |
11 | + var checkBox = textArea.parents('#cycle-new-mail').find('input[type=checkbox]') | |
12 | + checkBox.prop('checked', checked) | |
13 | + }, | |
14 | + }, | |
15 | + }, | |
16 | + | |
17 | + products: { | |
18 | + load_url: null, | |
19 | + | |
20 | + load: function () { | |
21 | + $.get(orders_cycle.cycle.products.load_url, function(data) { | |
22 | + if (data.length > 10) | |
23 | + $('#cycle-products .table').html(data) | |
24 | + else | |
25 | + setTimeout(orders_cycle.cycle.products.load, 5*1000); | |
26 | + }); | |
27 | + | |
28 | + }, | |
29 | + }, | |
30 | + }, | |
31 | + | |
32 | + /* ----- cycle ----- */ | |
33 | + | |
34 | + in_cycle_order_toggle: function (context) { | |
35 | + container = $(context).hasClass('cycle-orders') ? $(context) : $(context).parents('.cycle-orders'); | |
36 | + container.toggleClass('show'); | |
37 | + container.find('.order-content').toggle(); | |
38 | + sortable_table.edit_arrow_toggle(container); | |
39 | + }, | |
40 | + | |
41 | + /* ----- order ----- */ | |
42 | + | |
43 | + order: { | |
44 | + | |
45 | + load: function() { | |
46 | + $('html').click(function(e) { | |
47 | + $('.popover').remove() | |
48 | + }) | |
49 | + }, | |
50 | + | |
51 | + product: { | |
52 | + include_message: '', | |
53 | + order_id: 0, | |
54 | + redirect_after_include: '', | |
55 | + add_url: '', | |
56 | + remove_url: '', | |
57 | + balloon_url: '', | |
58 | + | |
59 | + load: function (id, state) { | |
60 | + var product = $('#cycle-product-'+id); | |
61 | + product.toggleClass('in-order', state); | |
62 | + product.find('input').get(0).checked = state; | |
63 | + toggle_edit.value_row.reload(); | |
64 | + return product; | |
65 | + }, | |
66 | + | |
67 | + showMore: function (url) { | |
68 | + $.get(url, function (data) { | |
69 | + var newProducts = $(data).filter('#cycle-products').find('.table-content').children() | |
70 | + $('.pagination').replaceWith(newProducts) | |
71 | + pagination.loading = false | |
72 | + }) | |
73 | + }, | |
74 | + | |
75 | + click: function (event, id) { | |
76 | + // was this a child click? | |
77 | + if (event != null && event.target != this && event.target.onclick) | |
78 | + return; | |
79 | + | |
80 | + var product = $('#cycle-product-'+id); | |
81 | + if (! product.hasClass('editable')) | |
82 | + return; | |
83 | + | |
84 | + var state = !product.hasClass('in-order'); | |
85 | + if (state == true) | |
86 | + this.add(id); | |
87 | + else | |
88 | + this.remove(id); | |
89 | + product.find('input').get(0).checked = state; | |
90 | + }, | |
91 | + | |
92 | + setEditable: function (editable) { | |
93 | + $('.order-cycle-product').toggleClass('editable', editable) | |
94 | + if (editable) | |
95 | + $('.order-cycle-product #product_ids_').removeAttr('disabled') | |
96 | + else | |
97 | + $('.order-cycle-product #product_ids_').attr('disabled', 'disabled') | |
98 | + }, | |
99 | + | |
100 | + add: function (id) { | |
101 | + var product = this.load(id, true); | |
102 | + | |
103 | + if (this.include_message) | |
104 | + alert(this.include_message); | |
105 | + | |
106 | + loading_overlay.show(product); | |
107 | + $.post(this.add_url, {order_id: this.order_id, redirect: this.redirect_after_include, offered_product_id: id}, function () { | |
108 | + loading_overlay.hide(product); | |
109 | + }, 'script'); | |
110 | + }, | |
111 | + remove: function (id) { | |
112 | + var product = this.load(id, false); | |
113 | + | |
114 | + loading_overlay.show(product); | |
115 | + $.post(this.remove_url, {id: id, order_id: this.order_id}, function () { | |
116 | + loading_overlay.hide(product); | |
117 | + }, 'script'); | |
118 | + }, | |
119 | + | |
120 | + supplier: { | |
121 | + balloon_url: '', | |
122 | + | |
123 | + balloon: function (id) { | |
124 | + var product = $('#cycle-product-'+id) | |
125 | + var target = product.find('.supplier') | |
126 | + var supplier_id = product.attr('supplier-id') | |
127 | + $.get(this.balloon_url+'/'+supplier_id, function(data) { | |
128 | + var html = $(data) | |
129 | + var title = orders_cycle.order.product.balloon_title(html) | |
130 | + // use container to avoid conflict with row click | |
131 | + var options = {html: true, content: html, container: 'body', title: title} | |
132 | + target.popover(options).popover('show') | |
133 | + }) | |
134 | + }, | |
135 | + }, | |
136 | + | |
137 | + balloon: function (id) { | |
138 | + var product = $('#cycle-product-'+id); | |
139 | + var target = product.find('.product'); | |
140 | + $.get(this.balloon_url+'/'+id, function(data) { | |
141 | + var html = $(data) | |
142 | + var title = orders_cycle.order.product.balloon_title(html) | |
143 | + // use container to avoid conflict with row click | |
144 | + var options = {html: true, content: html, container: 'body', title: title} | |
145 | + target.popover(options).popover('show') | |
146 | + }) | |
147 | + }, | |
148 | + | |
149 | + balloon_title: function(content) { | |
150 | + var titleElement = $(content).find('.popover-title') | |
151 | + var title = titleElement.html() | |
152 | + titleElement.hide() | |
153 | + return title | |
154 | + }, | |
155 | + }, // product | |
156 | + }, // order | |
157 | + | |
158 | + /* ----- cycle editions ----- */ | |
159 | + | |
160 | + offered_product: { | |
161 | + | |
162 | + pmsync: function (context, to_price) { | |
163 | + p = $(context).parents('.cycle-product .box-edit'); | |
164 | + margin = p.find('#product_margin_percentage'); | |
165 | + price = p.find('#product_price'); | |
166 | + buy_price = p.find('#product_buy_price'); | |
167 | + original_price = p.find('#product_original_price'); | |
168 | + base_price = unlocalize_currency(buy_price.val()) ? buy_price : original_price; | |
169 | + | |
170 | + if (to_price) | |
171 | + suppliers.price.calculate(price, margin, base_price); | |
172 | + else | |
173 | + suppliers.margin.calculate(margin, price, base_price); | |
174 | + }, | |
175 | + | |
176 | + edit: function () { | |
177 | + toggle_edit.editing().find('.box-edit').toggle(toggle_edit.isEditing()); | |
178 | + }, | |
179 | + }, | |
180 | + | |
181 | + /* ----- toggle edit ----- */ | |
182 | + | |
183 | + cycle_mail_message_toggle: function () { | |
184 | + if ($('#cycle-new-mail-send').prop('checked')) { | |
185 | + $('#cycle-new-mail').removeClass('disabled'); | |
186 | + $('#cycle-new-mail textarea').removeAttr('disabled'); | |
187 | + } else { | |
188 | + $('#cycle-new-mail').addClass('disabled'); | |
189 | + $('#cycle-new-mail textarea').attr('disabled', true); | |
190 | + } | |
191 | + }, | |
192 | + | |
193 | + ajaxifyPagination: function(selector) { | |
194 | + $(selector).find(".pagination a").click(function() { | |
195 | + loading_overlay.show(selector); | |
196 | + $.ajax({ | |
197 | + type: "GET", | |
198 | + url: $(this).attr("href"), | |
199 | + dataType: "script" | |
200 | + }); | |
201 | + return false; | |
202 | + }); | |
203 | + }, | |
204 | + | |
205 | + toggleCancelledOrders: function () { | |
206 | + $('.consumers-coop #show-cancelled-orders a').toggle(); | |
207 | + $('.consumers-coop #hide-cancelled-orders a').toggle(); | |
208 | + $('.consumers-coop .consumer-order.cancelled').not('.comsumer-order.active-order').toggle(); | |
209 | + }, | |
210 | + | |
211 | +}; | ... | ... |
plugins/orders_cycle/public/stylesheets/_orders-variables.scss
0 → 120000
plugins/orders_cycle/public/stylesheets/_sortable-table.scss
0 → 120000
plugins/orders_cycle/public/stylesheets/orders_cycle.scss
0 → 100644
... | ... | @@ -0,0 +1,620 @@ |
1 | +@import 'base'; | |
2 | +@import 'orders-variables'; | |
3 | + | |
4 | +@import 'sortable-table'; | |
5 | + | |
6 | +.balloon-content.orders-cycle { | |
7 | + @extend .container-clean; | |
8 | + // the size is defined on .balloon .content (see above) | |
9 | + | |
10 | + .left-column { | |
11 | + width: $module01; | |
12 | + margin-right: $half-margin; | |
13 | + float: left; | |
14 | + } | |
15 | + .right-column { | |
16 | + width: $module02; | |
17 | + float: right; | |
18 | + } | |
19 | + | |
20 | +} | |
21 | + | |
22 | +.cycle-view { | |
23 | + | |
24 | + #cycle-others, | |
25 | + #cycle-header { | |
26 | + padding-bottom: $padding; | |
27 | + margin-bottom: $half-margin; | |
28 | + margin-left: -2*$border; | |
29 | + padding-right: 2*$border; | |
30 | + } | |
31 | + #cycle-header { | |
32 | + border-bottom: 2*$border solid #ddd; | |
33 | + margin-bottom: 0; | |
34 | + | |
35 | + .subtitle, | |
36 | + #cycle-dates { | |
37 | + width: 520px; | |
38 | + | |
39 | + th { | |
40 | + border-bottom: 0; | |
41 | + } | |
42 | + } | |
43 | + | |
44 | + .subtitle { | |
45 | + display: block; | |
46 | + margin-top: 20px; | |
47 | + font-style: italic; | |
48 | + } | |
49 | + } | |
50 | + | |
51 | + #cycle-products-for-order { | |
52 | + width: $module06 + $intercolumn; | |
53 | + float: left; | |
54 | + padding-left: 0; | |
55 | + | |
56 | + .title { | |
57 | + } | |
58 | + | |
59 | + .balloon { | |
60 | + | |
61 | + .content { | |
62 | + width: $module03 + $intercolumn; //$intercolumn for scrollbars | |
63 | + max-height: 10*$height; | |
64 | + } | |
65 | + } | |
66 | + | |
67 | + #filter { | |
68 | + margin-left: -$sortable-table-negative-area; | |
69 | + | |
70 | + .title, .filter-box, .submit { | |
71 | + padding-left: $sortable-table-negative-area + $padding !important; | |
72 | + } | |
73 | + | |
74 | + .filter-box { | |
75 | + padding-left: $padding; | |
76 | + | |
77 | + &.fields { | |
78 | + | |
79 | + .supplier { | |
80 | + padding-left: 0; | |
81 | + } | |
82 | + .name { | |
83 | + padding-right: 0; | |
84 | + } | |
85 | + } | |
86 | + } | |
87 | + } | |
88 | + | |
89 | + #cycle-products { | |
90 | + | |
91 | + .table-header, .table-content { | |
92 | + margin-left: -$sortable-table-negative-area; | |
93 | + } | |
94 | + .table-header { | |
95 | + padding-left: $sortable-table-negative-area; | |
96 | + } | |
97 | + | |
98 | + | |
99 | + .table-content { | |
100 | + //override .product-pic from application.css | |
101 | + .product-pic { | |
102 | + max-width: 70px; | |
103 | + max-height: 70px; | |
104 | + } | |
105 | + } | |
106 | + | |
107 | + .box-field { | |
108 | + &, * { | |
109 | + text-overflow: ellipsis; | |
110 | + overflow: hidden; | |
111 | + white-space: nowrap; | |
112 | + } | |
113 | + &.category { | |
114 | + width: $module02 - 3*$base; | |
115 | + } | |
116 | + &.supplier { | |
117 | + width: $module02; | |
118 | + } | |
119 | + &.product { | |
120 | + width: $module02; | |
121 | + } | |
122 | + &.price-with-unit { | |
123 | + width: $module01; | |
124 | + } | |
125 | + } | |
126 | + | |
127 | + .value-row { | |
128 | + border: none; | |
129 | + | |
130 | + #product_ids_[disabled] { | |
131 | + display: none; | |
132 | + } | |
133 | + | |
134 | + &.in-order { | |
135 | + | |
136 | + .box-view { | |
137 | + background-color: $sortable-table-bg-yellow; | |
138 | + } | |
139 | + | |
140 | + } | |
141 | + } | |
142 | + } | |
143 | + } | |
144 | + | |
145 | + #order-column { | |
146 | + float: left; | |
147 | + width: $order-items-width; | |
148 | + margin-left: $margin; | |
149 | + padding: 0; | |
150 | + | |
151 | + > h3 { | |
152 | + margin-bottom: 2*$margin; | |
153 | + } | |
154 | + > h3 a { | |
155 | + text-transform: none; | |
156 | + float: right; | |
157 | + margin-left: $half-margin; | |
158 | + &:before { | |
159 | + padding-right: $half-padding; | |
160 | + } | |
161 | + } | |
162 | + | |
163 | + .consumer-order, | |
164 | + #order-page .in-order { | |
165 | + background-color: $sortable-table-bg-yellow; | |
166 | + } | |
167 | + .consumer-order { | |
168 | + margin-bottom: 10px; | |
169 | + width: $order-items-width; | |
170 | + | |
171 | + &.unactive { | |
172 | + .order-message-title { | |
173 | + float: left; | |
174 | + } | |
175 | + .actions { | |
176 | + float: right; | |
177 | + padding: $half-padding $padding; | |
178 | + } | |
179 | + &.cancelled { | |
180 | + display: none; | |
181 | + } | |
182 | + } | |
183 | + } | |
184 | + | |
185 | + #order-admin-warning { | |
186 | + background-color: #FECBCA; | |
187 | + } | |
188 | + | |
189 | + #order-admin-warning { | |
190 | + margin-bottom: $margin; | |
191 | + } | |
192 | + | |
193 | + .order-message { | |
194 | + padding: $padding; | |
195 | + } | |
196 | + | |
197 | + .order-message-text { | |
198 | + font-size: 10px; | |
199 | + font-style: italic; | |
200 | + } | |
201 | + .order-message-actions { | |
202 | + margin-top: $half-margin; | |
203 | + font-size: 10px; | |
204 | + } | |
205 | + | |
206 | + .order-message-actions a { | |
207 | + font-weight: bold; | |
208 | + } | |
209 | + | |
210 | + #close-order, | |
211 | + #desist-order { | |
212 | + margin-top: 30px; | |
213 | + margin-bottom: 8px; | |
214 | + } | |
215 | + | |
216 | + .quantity-entry input { | |
217 | + width: 76px; | |
218 | + } | |
219 | + } | |
220 | +} | |
221 | + | |
222 | +#cycle-admin-page { | |
223 | + @import 'field'; | |
224 | + | |
225 | + a.action-button { | |
226 | + margin-top: 5px; | |
227 | + } | |
228 | + #cycle-header-warning { | |
229 | + background-color: #FECBCA; | |
230 | + padding: 8px; | |
231 | + | |
232 | + #cycle-header-warning-wrap { | |
233 | + width: 70%; | |
234 | + | |
235 | + } | |
236 | + } | |
237 | + | |
238 | + #cycle-product-line .field { | |
239 | + width: 120px; | |
240 | + } | |
241 | + | |
242 | + #cycle-products { | |
243 | + margin-top: $margin; | |
244 | + | |
245 | + .header { | |
246 | + div { | |
247 | + width: 400px; | |
248 | + } | |
249 | + a { | |
250 | + line-height: 30px; | |
251 | + } | |
252 | + } | |
253 | + | |
254 | + .table { | |
255 | + .small-loading { | |
256 | + background-position: 0; | |
257 | + padding-left: 20px; | |
258 | + } | |
259 | + } | |
260 | + | |
261 | + .cycle-products-table { | |
262 | + margin-top: 30px; | |
263 | + } | |
264 | + .value-row.edit .price, | |
265 | + .value-row.edit .quantity-available, | |
266 | + .value-row.edit .actions { | |
267 | + visibility: hidden; | |
268 | + } | |
269 | + | |
270 | + .box-edit .field { | |
271 | + float: left; | |
272 | + clear: none; | |
273 | + margin-right: 40px; | |
274 | + width: 120px; | |
275 | + } | |
276 | + | |
277 | + .box-view .box-field { | |
278 | + } | |
279 | + .box-field.category { | |
280 | + width: 90px; | |
281 | + } | |
282 | + .box-field.supplier { | |
283 | + width: 120px; | |
284 | + } | |
285 | + .box-field.name { | |
286 | + width: 190px; | |
287 | + } | |
288 | + .box-field.price { | |
289 | + width: 160px; | |
290 | + } | |
291 | + .box-field.quantity-available { | |
292 | + width: 80px; | |
293 | + } | |
294 | + .quantity-available input { | |
295 | + width: 60px; | |
296 | + } | |
297 | + .box-edit input[type=text] { | |
298 | + width: 120px; | |
299 | + } | |
300 | + } | |
301 | +} | |
302 | + | |
303 | +#cycle-closed-listing { | |
304 | + padding-left: 0; | |
305 | +} | |
306 | + | |
307 | +#cycle-new-mail-send { | |
308 | + margin-bottom: 0; | |
309 | +} | |
310 | + | |
311 | +#cycle-new-mail label { | |
312 | + font-weight: bold; | |
313 | +} | |
314 | + | |
315 | +#cycle-new-mail .mail-message { | |
316 | + margin-top: 10px; | |
317 | +} | |
318 | + | |
319 | + | |
320 | +.cycle { | |
321 | + | |
322 | + .h2 { | |
323 | + margin-bottom: 0; | |
324 | + } | |
325 | + | |
326 | + .cycle-timeline { | |
327 | + border: 2*$border solid #CBCBCB; | |
328 | + margin-bottom: $margin; | |
329 | + @extend .container-clean; | |
330 | + | |
331 | + //wireframe size | |
332 | + width: $wireframe + 2*$wireframe-padding; | |
333 | + margin-left: -$wireframe-padding; | |
334 | + padding: 0 $wireframe-padding; | |
335 | + | |
336 | + &, | |
337 | + .cycle-timeline-passed-item, | |
338 | + .cycle-timeline-current-item { | |
339 | + background: url(/plugins/orders_cycle/images/progressbar.png) left top no-repeat; | |
340 | + } | |
341 | + & { | |
342 | + background-size: $wireframe-padding $wireframe-padding*2; //height is arbitrary big to fit | |
343 | + } | |
344 | + | |
345 | + .cycle-timeline-item { | |
346 | + float: left; | |
347 | + padding: $padding; | |
348 | + font-weight: bold; | |
349 | + | |
350 | + &:first-child { | |
351 | + padding-left: 0; | |
352 | + } | |
353 | + } | |
354 | + | |
355 | + .cycle-timeline-current-item { | |
356 | + background-position: 105% 0; | |
357 | + } | |
358 | + .cycle-timeline-next-item { | |
359 | + color: #BABABA; | |
360 | + } | |
361 | + .cycle-timeline-selected-item { | |
362 | + color: black; | |
363 | + text-decoration: none; | |
364 | + font-weight: bold; | |
365 | + } | |
366 | + | |
367 | + } | |
368 | + | |
369 | + .dates-brief { | |
370 | + margin-bottom: 2*$margin; | |
371 | + } | |
372 | + | |
373 | + .actions-bar { | |
374 | + clear: both; | |
375 | + } | |
376 | +} | |
377 | + | |
378 | + | |
379 | +.cycle-product-line *[disabled] { | |
380 | + background-color: transparent; | |
381 | +} | |
382 | + | |
383 | +#cycle-dates th { | |
384 | + width: 80px; | |
385 | + vertical-align: top; | |
386 | + border-bottom: 0; | |
387 | + | |
388 | + .cycle-list-item { | |
389 | + border-top: 1px dotted #ccc; | |
390 | + padding: 8px; | |
391 | + } | |
392 | + .cycle-list-item:last-child { | |
393 | + border-bottom: 1px dotted #ccc; | |
394 | + } | |
395 | + .cycle-name-and-code { | |
396 | + font-weight: bold; | |
397 | + } | |
398 | +} | |
399 | + | |
400 | +#orders-view { | |
401 | + | |
402 | + h2 { | |
403 | + margin-top: 20px; | |
404 | + } | |
405 | + | |
406 | + .consumer-orders { | |
407 | + | |
408 | + #cycle-others { | |
409 | + border-bottom: 2px dotted #aaa; | |
410 | + } | |
411 | + #consumer-new-order { | |
412 | + font-weight: bold; | |
413 | + } | |
414 | + | |
415 | + #order-place-new { | |
416 | + font-size: 10px; | |
417 | + border: $border solid #FFF0AD; | |
418 | + padding: $padding; | |
419 | + margin-bottom: 10px; | |
420 | + | |
421 | + &.admin { | |
422 | + font-size: 12px; | |
423 | + border: none; | |
424 | + float: right; | |
425 | + padding: $padding 0; | |
426 | + text-transform: lower; | |
427 | + } | |
428 | + } | |
429 | + | |
430 | + #years-filter { | |
431 | + margin-bottom: $margin; | |
432 | + | |
433 | + a { | |
434 | + font-weight: bold; | |
435 | + | |
436 | + &.current { | |
437 | + text-decoration: none; | |
438 | + color: black; | |
439 | + } | |
440 | + } | |
441 | + } | |
442 | + | |
443 | + .order-message-title { | |
444 | + float: left; | |
445 | + margin-right: 5px; | |
446 | + } | |
447 | + } | |
448 | + | |
449 | + .cycle-with-consumer-orders { | |
450 | + padding-bottom: 10px; | |
451 | + border-top: 2px dotted #aaa; | |
452 | + | |
453 | + &:last-child { | |
454 | + border-bottom: 2px dotted #aaa; | |
455 | + } | |
456 | + } | |
457 | + | |
458 | + .consumer-orders { | |
459 | + | |
460 | + > a { | |
461 | + float: left; | |
462 | + } | |
463 | + a { | |
464 | + text-decoration: none; | |
465 | + } | |
466 | + a div { | |
467 | + font-size: 10px; | |
468 | + color: black; | |
469 | + } | |
470 | + } | |
471 | +} | |
472 | + | |
473 | +.order-data .order-message-title.cancelled { | |
474 | + display: block; | |
475 | +} | |
476 | +.order-message-title { | |
477 | + padding: $half-padding $padding; | |
478 | + font-size: 13px; | |
479 | + font-weight: bold; | |
480 | + @extend .container-clean; | |
481 | + | |
482 | + div { | |
483 | + float: left; | |
484 | + background-size: 11px 30px; | |
485 | + } | |
486 | + | |
487 | + a.open { | |
488 | + display: none; | |
489 | + float: right; | |
490 | + font-weight: normal; | |
491 | + } | |
492 | + | |
493 | + &.open { | |
494 | + background-color: #FFF2A3; | |
495 | + div { | |
496 | + padding-left: 20px; | |
497 | + background: url(/plugins/orders_cycle/images/order-statuses.png) 0px -25px no-repeat; | |
498 | + padding-left: 24px; | |
499 | + margin-bottom: 0; | |
500 | + } | |
501 | + } | |
502 | + | |
503 | + &.ordered { | |
504 | + background-color: #E1F5C4; | |
505 | + div { | |
506 | + background: url(/plugins/orders_cycle/images/order-statuses.png) left -2px no-repeat; | |
507 | + padding-left: 24px; | |
508 | + } | |
509 | + } | |
510 | + | |
511 | + &.cancelled { | |
512 | + } | |
513 | + | |
514 | + &.cancelled, | |
515 | + &.forgotten { | |
516 | + background-color: #FECBCA; | |
517 | + } | |
518 | +} | |
519 | + | |
520 | +#cycles-gadget { | |
521 | + margin-bottom: 30px; | |
522 | + | |
523 | + #all-cycles { | |
524 | + float: right; | |
525 | + } | |
526 | + h2 { | |
527 | + color: #036475; | |
528 | + } | |
529 | + | |
530 | + td { | |
531 | + padding-right: 8px; | |
532 | + vertical-align: top; | |
533 | + } | |
534 | + td.first-column { | |
535 | + width: 300px; | |
536 | + } | |
537 | + td.second-column { | |
538 | + width: 400px; | |
539 | + } | |
540 | + td.third-column { | |
541 | + vertical-align: bottom; | |
542 | + } | |
543 | + td.third-column form { | |
544 | + float: right; | |
545 | + clear: both; | |
546 | + } | |
547 | + .cycle .happening { | |
548 | + background-color: #ffe546; | |
549 | + line-height: 20px; | |
550 | + text-transform: uppercase; | |
551 | + padding: 0 8px; | |
552 | + } | |
553 | + .cycle .info { | |
554 | + background: #DDF2C5; | |
555 | + padding: 8px; | |
556 | + padding-right: 0; | |
557 | + } | |
558 | +} | |
559 | + | |
560 | +#cycle_opening_message { | |
561 | + margin-bottom: $intercolumn; | |
562 | + width: 420px; | |
563 | +} | |
564 | + | |
565 | +#cycle-fields input { | |
566 | + margin-right: 7px; | |
567 | +} | |
568 | +.cycle-field-name input { | |
569 | + width: 195px; | |
570 | +} | |
571 | +.cycle-fields-block { | |
572 | + margin: 10px 0; | |
573 | +} | |
574 | +.cycle-field-description textarea { | |
575 | + width: 412px; | |
576 | + height: 100px; | |
577 | +} | |
578 | + | |
579 | +.action-orders_cycle_plugin_cycle-new .cycle-edit-link, | |
580 | +.action-orders_cycle_plugin_cycle-edit .cycle-edit-link { | |
581 | + height: 44px; | |
582 | + display: block; | |
583 | +} | |
584 | + | |
585 | +#cycle-delivery-options { | |
586 | + clear: both; | |
587 | +} | |
588 | +#cycle-delivery label { | |
589 | + font-weight: bold; | |
590 | +} | |
591 | + | |
592 | +.cycle-new { | |
593 | + margin-bottom: 29px; | |
594 | + display: block; | |
595 | +} | |
596 | + | |
597 | +.cycle-delivery-option { | |
598 | + float: left; | |
599 | + display: inline-block; | |
600 | + padding: 2px 5px; | |
601 | + margin-right: 10px; | |
602 | + background-color: #E5E0EC; | |
603 | + border-radius: 4px; | |
604 | + -moz-border-radius: 4px; | |
605 | + -webkit-border-radius: 4px; | |
606 | + -o-border-radius: 4px; | |
607 | +} | |
608 | + | |
609 | +.action-orders_cycle_plugin_cycle-new #colorbox, .action-orders_cycle_plugin_cycle-edit #colorbox { | |
610 | + top: 80%; | |
611 | +} | |
612 | + | |
613 | +#cycle-orders { | |
614 | + margin-top: $margin; | |
615 | + | |
616 | +} | |
617 | + | |
618 | +.distribution-plugin-popin { | |
619 | + padding: 10px; | |
620 | +} | ... | ... |
... | ... | @@ -0,0 +1,57 @@ |
1 | +module OrdersCyclePlugin::Factory | |
2 | + | |
3 | + def defaults_for_suppliers_plugin_supplier | |
4 | + {:profile => build(Profile), | |
5 | + :consumer => build(Profile)} | |
6 | + end | |
7 | + | |
8 | + def defaults_for_suppliers_plugin_distributed_product attrs = {} | |
9 | + profile = attrs[:profile] || build(Profile) | |
10 | + {:profile => profile, :name => "product-#{factory_num_seq}", :price => 2.0, | |
11 | + :product => build(Product, :enterprise => profile.profile, :price => 2.0), | |
12 | + :supplier => build(SuppliersPlugin::Supplier, :profile => profile, :consumer => profile)} | |
13 | + end | |
14 | + | |
15 | + def defaults_for_orders_cycle_plugin_offered_product attrs = {} | |
16 | + hash = defaults_for_orders_cycle_plugin_product(attrs) | |
17 | + profile = hash[:profile] | |
18 | + hash.merge({ | |
19 | + :from_products => [build(SuppliersPlugin::DistributedProduct, :profile => profile)]}) | |
20 | + end | |
21 | + | |
22 | + def defaults_for_delivery_plugin_method | |
23 | + {:profile => build(OrdersCyclePlugin::Profile), | |
24 | + :name => "My delivery #{factory_num_seq.to_s}", | |
25 | + :delivery_type => 'deliver'} | |
26 | + end | |
27 | + | |
28 | + def defaults_for_delivery_plugin_option | |
29 | + {:cycle => build(OrdersCyclePlugin::Cycle), | |
30 | + :delivery_method => build(DeliveryPlugin::Method)} | |
31 | + end | |
32 | + | |
33 | + def defaults_for_orders_plugin_order attrs = {} | |
34 | + profile = attrs[:profile] || build(OrdersCyclePlugin::Profile) | |
35 | + {:status => 'ordered', | |
36 | + :cycle => build(OrdersCyclePlugin::Cycle, :profile => profile), | |
37 | + :consumer => build(OrdersCyclePlugin::Profile), | |
38 | + :supplier_delivery => build(DeliveryPlugin::Method, :profile => profile), | |
39 | + :consumer_delivery => build(DeliveryPlugin::Method, :profile => profile)} | |
40 | + end | |
41 | + | |
42 | + def defaults_for_orders_plugin_items | |
43 | + {:order => build(OrdersPlugin::Order), | |
44 | + :product => build(OrdersCyclePlugin::OfferedProduct), | |
45 | + :quantity_shipped => 1.0, :quantity_ordered => 2.0, :quantity_accepted => 3.0, | |
46 | + :price_shipped => 10.0, :price_ordered => 20.0, :price_accepted => 30.0} | |
47 | + end | |
48 | + | |
49 | + def defaults_for_orders_cycle_plugin_cycle | |
50 | + {:profile => build(OrdersCyclePlugin::Profile), :status => 'orders', | |
51 | + :name => 'weekly', :start => Time.now, :finish => Time.now+1.days} | |
52 | + end | |
53 | + | |
54 | +end | |
55 | + | |
56 | +Noosfero::Factory.register_extension OrdersCyclePlugin::Factory | |
57 | + | ... | ... |
plugins/orders_cycle/test/functional/orders_cycle_plugin/order_controller_test.rb
0 → 100644
... | ... | @@ -0,0 +1,12 @@ |
1 | +require "#{File.dirname(__FILE__)}/../../test_helper" | |
2 | + | |
3 | +class OrdersCyclePlugin::OrderControllerTest < Test::Unit::TestCase | |
4 | + | |
5 | + def setup | |
6 | + @controller = OrdersCyclePluginOrderController.new | |
7 | + @request = ActionController::TestRequest.new | |
8 | + @response = ActionController::TestResponse.new | |
9 | + end | |
10 | + | |
11 | + | |
12 | +end | ... | ... |
plugins/orders_cycle/test/functional/orders_cycle_plugin/session_controller_test.rb
0 → 100644
... | ... | @@ -0,0 +1,14 @@ |
1 | +require "#{File.dirname(__FILE__)}/../../test_helper" | |
2 | + | |
3 | +class OrdersCyclePlugin::CycleControllerTest < Test::Unit::TestCase | |
4 | + | |
5 | + def setup | |
6 | + @controller = OrdersCyclePluginCycleController.new | |
7 | + @request = ActionController::TestRequest.new | |
8 | + @response = ActionController::TestResponse.new | |
9 | + end | |
10 | + | |
11 | + should 'create a new cycle' do | |
12 | + end | |
13 | + | |
14 | +end | ... | ... |
plugins/orders_cycle/test/unit/orders_cycle_plugin/cycle_test.rb
0 → 100644
... | ... | @@ -0,0 +1,27 @@ |
1 | +require "#{File.dirname(__FILE__)}/../../test_helper" | |
2 | + | |
3 | +class OrdersCyclePlugin::CycleTest < ActiveSupport::TestCase | |
4 | + | |
5 | + def setup | |
6 | + @profile = Enterprise.create!(:name => "trocas verdes", :identifier => "trocas-verdes") | |
7 | + @pc = ProductCategory.create!(:name => 'frutas', :environment_id => 1) | |
8 | + @profile.products = [Product.create!(:name => 'banana', :product_category => @pc), | |
9 | + Product.new(:name => 'mandioca', :product_category => @pc), Product.new(:name => 'alface', :product_category => @pc)] | |
10 | + | |
11 | + profile.offered_products = @profile.products.map{ |p| OrdersCyclePlugin::OfferedProduct.create!(:product => p) } | |
12 | + DeliveryPlugin::Method.create! :name => 'at home', :delivery_type => 'pickup', :profile => @profile | |
13 | + @cycle = OrdersCyclePlugin::Cycle.create!(:profile => @profile) | |
14 | + end | |
15 | + | |
16 | + should 'add products from profile after create' do | |
17 | + assert_equal @cycle.products.collect(&:product_id), @profile.products.collect(&:id) | |
18 | + end | |
19 | + | |
20 | + should 'have at least one delivery method unless in edition status' do | |
21 | + cycle = OrdersCyclePlugin::Cycle.create! :profile => @profile, :name => "Testes batidos", :start => DateTime.now, :status => 'edition' | |
22 | + assert cycle | |
23 | + cycle.status = 'orders' | |
24 | + assert_nil cycle.save! | |
25 | + end | |
26 | + | |
27 | +end | ... | ... |
plugins/orders_cycle/test/unit/orders_cycle_plugin/offered_product_test.rb
0 → 100644
... | ... | @@ -0,0 +1,127 @@ |
1 | +require "#{File.dirname(__FILE__)}/../../test_helper" | |
2 | + | |
3 | +class OrdersCyclePlugin::ProfileTest < ActiveRecord::TestCase | |
4 | + | |
5 | + def setup | |
6 | + @profile = build(Profile) | |
7 | + @invisible_profile = build(Enterprise, :visible => false) | |
8 | + @other_profile = build(Enterprise) | |
9 | + @profile = build(OrdersCyclePlugin::profile, :profile => @profile) | |
10 | + @self_supplier = build(OrdersCyclePlugin::Supplier, :consumer => @profile, :profile => @profile) | |
11 | + @dummy_supplier = build(OrdersCyclePlugin::Supplier, :consumer => @profile, :profile => @dummy_profile) | |
12 | + @other_supplier = build(OrdersCyclePlugin::Supplier, :consumer => @profile, :profile => @other_profile) | |
13 | + end | |
14 | + | |
15 | + attr_accessor :profile, :invisible_profile, :other_profile, | |
16 | + :self_supplier, :dummy_supplier, :other_supplier | |
17 | + | |
18 | + should 'respond to name methods' do | |
19 | + profile.expects(:name).returns('name') | |
20 | + assert_equal 'name', profile.name | |
21 | + end | |
22 | + | |
23 | + should 'respond to dummy methods' do | |
24 | + profile.dummy = true | |
25 | + assert_equal true, profile.dummy? | |
26 | + profile.dummy = false | |
27 | + assert_equal false, profile.dummy | |
28 | + end | |
29 | + | |
30 | + should "return closed cycles' date range" do | |
31 | + DateTime.expects(:now).returns(1).at_least_once | |
32 | + assert_equal 1..1, profile.orders_cycles_closed_date_range | |
33 | + s1 = create(OrdersCyclePlugin::Cycle, :profile => profile, :start => Time.now-1.days, :finish => nil) | |
34 | + s2 = create(OrdersCyclePlugin::Cycle, :profile => profile, :finish => Time.now+1.days, :start => Time.now) | |
35 | + assert_equal (s1.start.to_date..s2.finish.to_date), profile.orders_cycles_closed_date_range | |
36 | + end | |
37 | + | |
38 | + should 'return abbreviation or the name' do | |
39 | + profile.name_abbreviation = 'coll.' | |
40 | + profile.profile.name = 'collective' | |
41 | + assert_equal 'coll.', profile.abbreviation_or_name | |
42 | + profile.name_abbreviation = nil | |
43 | + assert_equal 'collective', profile.abbreviation_or_name | |
44 | + end | |
45 | + | |
46 | + ### | |
47 | + # Products | |
48 | + ### | |
49 | + | |
50 | + should "default products's margins when asked" do | |
51 | + profile.update_attributes! :margin_percentage => 10 | |
52 | + product = create(SuppliersPlugin::DistributedProduct, :profile => profile, :supplier => profile.self_supplier, | |
53 | + :price => 10, :default_margin_percentage => false) | |
54 | + cycle = create(OrdersCyclePlugin::Cycle, :profile => profile) | |
55 | + sproduct = cycle.products.first | |
56 | + sproduct.update_attributes! :margin_percentage => 5 | |
57 | + cycleclosed = create(OrdersCyclePlugin::Cycle, :profile => profile, :status => 'closed') | |
58 | + | |
59 | + profile.orders_cycles_products_default_margins | |
60 | + product.reload | |
61 | + sproduct.reload | |
62 | + assert_equal true, product.default_margin_percentage | |
63 | + assert_equal sproduct.margin_percentage, profile.margin_percentage | |
64 | + end | |
65 | + | |
66 | + should 'return not yet distributed products' do | |
67 | + profile.save! | |
68 | + other_profile.save! | |
69 | + other_supplier.save! | |
70 | + product = create(SuppliersPlugin::DistributedProduct, :profile => other_profile, :supplier => other_profile.self_supplier) | |
71 | + profile.add_supplier_products other_supplier | |
72 | + product2 = create(SuppliersPlugin::DistributedProduct, :profile => other_profile, :supplier => other_profile.self_supplier) | |
73 | + assert_equal [product2], profile.not_distributed_products(other_supplier) | |
74 | + end | |
75 | + | |
76 | + ### | |
77 | + # Suppliers | |
78 | + ### | |
79 | + | |
80 | + should 'add supplier' do | |
81 | + @profile.save! | |
82 | + @other_profile.save! | |
83 | + | |
84 | + assert_difference OrdersCyclePlugin::Supplier, :count do | |
85 | + @profile.add_supplier @other_profile | |
86 | + end | |
87 | + assert @profile.suppliers_profiles.include?(@other_profile) | |
88 | + assert @other_profile.consumers_profiles.include?(@profile) | |
89 | + end | |
90 | + | |
91 | + should "add all supplier's products when supplier is added" do | |
92 | + @profile.save! | |
93 | + @other_profile.save! | |
94 | + product = create(SuppliersPlugin::DistributedProduct, :profile => @other_profile) | |
95 | + @profile.add_supplier @other_profile | |
96 | + assert_equal [product], @profile.from_products | |
97 | + end | |
98 | + | |
99 | + should 'remove supplier' do | |
100 | + @profile.save! | |
101 | + @other_profile.save! | |
102 | + | |
103 | + @profile.add_supplier @other_profile | |
104 | + assert_difference OrdersCyclePlugin::Supplier, :count, -1 do | |
105 | + assert_difference RoleAssignment, :count, -1 do | |
106 | + @profile.remove_supplier @other_profile | |
107 | + end | |
108 | + end | |
109 | + assert !@profile.suppliers_profiles.include?(@other_profile) | |
110 | + end | |
111 | + | |
112 | + should "archive supplier's products when supplier is removed" do | |
113 | + @profile.save! | |
114 | + @other_profile.save! | |
115 | + product = create(SuppliersPlugin::DistributedProduct, :profile => @other_profile) | |
116 | + @profile.add_supplier @other_profile | |
117 | + @profile.remove_supplier @other_profile | |
118 | + assert_equal [product], @profile.from_products | |
119 | + assert_equal 1, @profile.distributed_products.archived.count | |
120 | + end | |
121 | + | |
122 | + should 'create self supplier automatically' do | |
123 | + profile = create(OrdersCyclePlugin::profile, :profile => @profile) | |
124 | + assert_equal 1, profile.suppliers.count | |
125 | + end | |
126 | + | |
127 | +end | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin/mailer/open_cycle.html.erb
0 → 100644
... | ... | @@ -0,0 +1,28 @@ |
1 | +<!DOCTYPE html> | |
2 | +<html> | |
3 | + <head> | |
4 | + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | |
5 | + </head> | |
6 | + <body> | |
7 | + <p> | |
8 | + <%= t('views.mailer.open_cycle.hello_member_of_name') % {:name => @profile.name} %> | |
9 | + </p> | |
10 | + | |
11 | + <p><%= t('views.mailer.open_cycle.a_new_cycle_is_open_c') + @cycle.name %></p> | |
12 | + <hr /> | |
13 | + <p><i><%= @cycle.description %></i></p> | |
14 | + <hr /> | |
15 | + <p><%= t('views.mailer.open_cycle.the_administrator_let') %></p> | |
16 | + <p><i><%= @message %></i></p> | |
17 | + | |
18 | + <p><%= link_to t('views.order.index.place_an_order'), {:controller => :orders_cycle_plugin_order, :action => :edit, :cycle_id => @cycle.id, :profile => @profile.identifier, :only_path => false, :host => @profile.hostname || @environment.default_hostname }, :id => 'consumer-new-order' %></p> | |
19 | + | |
20 | + <p><%= @domain %> | |
21 | + <p> | |
22 | + --<br/> | |
23 | + </p> | |
24 | + | |
25 | + <small style="color: #888"><%= @environment.name %></small> | |
26 | + </body> | |
27 | +</html> | |
28 | + | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_closed.html.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_closing.html.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_cycle_purchases.html.slim
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_cycle_sales.html.slim
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_delivery.html.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_edit_fields.html.slim
0 → 100644
... | ... | @@ -0,0 +1,58 @@ |
1 | += render 'orders_plugin/shared/daterangepicker/init' | |
2 | + | |
3 | +h3= t('views.cycle._edit_fields.general_settings') | |
4 | + | |
5 | += form_for @cycle, as: :cycle , remote: true, url: {action: @cycle.new? ? :new : :edit, id: @cycle.id }, html: {data: {loading: '#cycle-fields form'}} do |f| | |
6 | + | |
7 | + = labelled_field f, :name, t('views.cycle._edit_fields.name'), f.text_field(:name), class: 'cycle-field-name' | |
8 | + = labelled_field f, :description, t('views.cycle._edit_fields.description'), f.text_area(:description, class: 'mceEditor'), class: 'cycle-field-description' | |
9 | + = render file: 'shared/tiny_mce', locals: {mode: 'simple'} | |
10 | + | |
11 | + .cycle-fields-block | |
12 | + = labelled_datetime_range_field f, :start, :finish, t('views.cycle._edit_fields.orders_interval'), class: 'cycle-orders-period' | |
13 | + .cycle-fields-block | |
14 | + = labelled_datetime_range_field f, :delivery_start, :delivery_finish, t('views.cycle._edit_fields.deliveries_interval'), class: 'cycle-orders-period' | |
15 | + | |
16 | + .cycle-fields-block | |
17 | + #cycle-delivery.field | |
18 | + = f.label :delivery_methods, t('views.cycle._edit_fields.available_delivery_me') | |
19 | + div | |
20 | + #cycle-delivery-options.subtitle | |
21 | + = render 'delivery_plugin/admin_options/index', owner: @cycle | |
22 | + = modal_link_to t('views.cycle._edit_fields.add_method'), | |
23 | + {controller: :orders_cycle_plugin_delivery_option, action: :select, owner_id: @cycle.id, owner_type: @cycle.class.name}, | |
24 | + class: 'subtitle' | |
25 | + | | |
26 | + = link_to_function t('views.cycle._edit_fields.add_all_methods'), | |
27 | + "$.getScript('#{url_for controller: :orders_cycle_plugin_delivery_option, action: :select_all, owner_id: @cycle.id, owner_type: @cycle.class.name}')", | |
28 | + class: 'subtitle' | |
29 | + .clean | |
30 | + | |
31 | + - if profile.volunteers_settings.cycle_volunteers_enabled | |
32 | + = render 'volunteers_plugin_myprofile/edit_periods', owner: @cycle, f: f | |
33 | + | |
34 | + #cycle-new-mail | |
35 | + = check_box_tag('sendmail', 'yes', false, id: 'cycle-new-mail-send') | |
36 | + = content_tag('label', t('views.cycle._edit_fields.notify_members_of_ope'), for: 'sendmail') | |
37 | + .mail-message | |
38 | + = f.label :sendmail, t('views.cycle._edit_fields.opening_message') | |
39 | + div= t('views.cycle._edit_fields.this_message_will_be_') | |
40 | + = f.text_area(:opening_message, onkeyup: 'orders_cycle.cycle.edit.openingMessage.onKeyup(this)') | |
41 | + javascript: | |
42 | + $('#cycle-new-mail-send').on('click', orders_cycle.cycle_mail_message_toggle) | |
43 | + | |
44 | + - submit_text = if @cycle.new? then t('views.cycle._edit_fields.create_new_cycle') else t('views.cycle._edit_fields.save') end | |
45 | + = f.submit submit_text | |
46 | + - unless @cycle.passed_by? 'edition' | |
47 | + | | |
48 | + = hidden_field_tag 'open', nil | |
49 | + - text = t("views.cycle._edit_fields.#{if @cycle.new? then 'create' else 'save' end}_and_open_orders") | |
50 | + = f.submit text, onclick: "this.form.elements['open'].value = '1'" | |
51 | + | |
52 | + | | |
53 | + = link_to t('views.cycle._edit_fields.cancel_changes'), @cycle.new? ? {action: :index} : params | |
54 | + - unless @cycle.new? | |
55 | + | | |
56 | + = link_to t('views.cycle._edit_fields.remove'), {action: :destroy, id: @cycle.id}, confirm: t('views.cycle._edit_fields.confirm_remove') | |
57 | + | |
58 | + | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_edit_popin.html.erb
0 → 100644
... | ... | @@ -0,0 +1,18 @@ |
1 | +<div class="popin"> | |
2 | + <h1><%= t('views.cycle._edit_popin.cycle_editing') %></h1> | |
3 | + | |
4 | + <div> | |
5 | + <% if cycle.valid? %> | |
6 | + <%= t('views.cycle._edit_popin.cycle_saved') %> | |
7 | + <% else %> | |
8 | + <% cycle.errors.full_messages.each do |msg| %> | |
9 | + <div><%= msg %></div> | |
10 | + <% end %> | |
11 | + <% end %> | |
12 | + </div> | |
13 | + | |
14 | + <div> | |
15 | + <%= modal_close_button t('views.cycle._edit_popin.close') %> | |
16 | + </div> | |
17 | + | |
18 | +</div> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_edition.html.erb
0 → 100644
... | ... | @@ -0,0 +1,26 @@ |
1 | +<% if @cycle.passed_by? 'edition' %> | |
2 | + <%= render 'title', :title => t('views.cycle._edition.info') %> | |
3 | +<% end %> | |
4 | + | |
5 | +<div id="cycle-fields"> | |
6 | + <%= render 'edit_fields' %> | |
7 | +</div> | |
8 | + | |
9 | +<div id='cycle-products'> | |
10 | + <div class="header"> | |
11 | + <h3><%= t('views.cycle._edition.the_products') %></h3> | |
12 | + | |
13 | + <div class="subtitle"><%= t('views.cycle._edition.the_following_list_of') %></div> | |
14 | + <div class="subtitle"><%= t('views.cycle._edition.it_was_automatically_') %></div> | |
15 | + </div> | |
16 | + | |
17 | + <div class="table"> | |
18 | + <% if @cycle.add_products_job %> | |
19 | + <%= render 'products_loading' %> | |
20 | + <% else %> | |
21 | + <%= render 'product_lines' %> | |
22 | + <% end %> | |
23 | + </div> | |
24 | + | |
25 | +</div> | |
26 | + | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_filter_fields.html.erb
0 → 100644
... | ... | @@ -0,0 +1,15 @@ |
1 | +<div class="field year"> | |
2 | + <label><%=t('orders_cycle_plugin.views.cycle.index.show_cycles_from_year') %></label> | |
3 | + <div> | |
4 | + <% range = @profile.orders_cycles_closed_date_range %> | |
5 | + <%= select_year @year_date, {:prompt => '', :start_year => range.first.year, :end_year => range.last.year} %> | |
6 | + </div> | |
7 | +</div> | |
8 | + | |
9 | +<div class="field month"> | |
10 | + <label><%=t('orders_cycle_plugin.views.cycle.index.and_are_from_the_mont') %></label> | |
11 | + <div> | |
12 | + <%= select_month @month_date, {:prompt => '' } %> | |
13 | + </div> | |
14 | +</div> | |
15 | + | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_header.html.erb
0 → 100644
... | ... | @@ -0,0 +1,18 @@ |
1 | +<% | |
2 | + actions = true if actions.nil? and @admin | |
3 | + timeline = true if actions.nil? and @admin | |
4 | + listing = false if listing.nil? | |
5 | +%> | |
6 | + | |
7 | +<h2> | |
8 | + <% if cycle.new? %> | |
9 | + <div class="cycle-edit-link"><%= t('views.cycle._title.new_cycle') %></div> | |
10 | + <% else %> | |
11 | + <%= link_to "#{t('views.cycle._title.order_cycle') if not listing}#{cycle.name_with_code}", {:action => 'edit', :id => cycle.id }, :class => "cycle-edit-link" %> | |
12 | + <% end %> | |
13 | + | |
14 | + <%= t('views.cycle._brief.confirmed_orders', :count => cycle.sales.ordered.count) if listing and not cycle.new? %> | |
15 | +</h2> | |
16 | + | |
17 | +<%= render 'timeline', :cycle => cycle, :actions => actions, :listing => listing if timeline %> | |
18 | + | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_orders.html.erb
0 → 100644
... | ... | @@ -0,0 +1,14 @@ |
1 | +<div class="subtitle"> | |
2 | + <%= hideable_help_text t('views.cycle._orders.header_help') %> | |
3 | +</div> | |
4 | + | |
5 | +<% if @cycle.orders? or @cycle.passed_by? 'orders' %> | |
6 | + <% if @cycle.orders? %> | |
7 | + <% header = t('views.cycle._orders.the_orders_period_is_') %> | |
8 | + <% elsif @cycle.passed_by? 'orders' %> | |
9 | + <% header = t('views.cycle._orders.already_closed') %> | |
10 | + <% end %> | |
11 | +<% end %> | |
12 | + | |
13 | +<%= render 'orders_cycle_plugin_cycle/cycle_sales' %> | |
14 | + | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_product_lines.html.erb
0 → 100644
... | ... | @@ -0,0 +1,30 @@ |
1 | +<div class="cycle-products-table sortable-table"> | |
2 | + <%= pagination_links @products %> | |
3 | + <div id="result-count"> | |
4 | + <small><%= t('views.cycle._product_lines.showing_pcount_produc') % {:pcount => @products.length, :allpcount => @cycle.products.count} %></small> | |
5 | + </div> | |
6 | + <div class='table-header'> | |
7 | + <span class='box-field category'><%= t('views.cycle._product_lines.category') %></span> | |
8 | + <span class='box-field supplier'><%= t('views.cycle._product_lines.supplier') %></span> | |
9 | + <span class='box-field name'><%= t('views.cycle._product_lines.product') %></span> | |
10 | + <span class="box-field price"><%= t('views.cycle._product_lines.price') %></span> | |
11 | + <span class="box-field quantity-available"><%= t('views.cycle._product_lines.qty_avail') %></span> | |
12 | + <span class="box-field actions"></span> | |
13 | + | |
14 | + <div class="clean"></div> | |
15 | + </div> | |
16 | + | |
17 | + <div class='table-content'> | |
18 | + <% @products.each do |p| %> | |
19 | + <div id="cycle-product-<%=p.id%>" class='cycle-product value-row' toggle-edit="orders_cycle.offered_product.edit();"> | |
20 | + <%= render 'orders_cycle_plugin_product/cycle_edit', :p => p %> | |
21 | + </div> | |
22 | + <% end %> | |
23 | + <%= javascript_tag do %> | |
24 | + jQuery(document).ready(function() { | |
25 | + orders_cycle.ajaxifyPagination("#cycle-products .table") | |
26 | + }) | |
27 | + <% end %> | |
28 | + </div> | |
29 | +</div> | |
30 | + | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_products_loading.html.erb
0 → 100644
... | ... | @@ -0,0 +1,9 @@ |
1 | + | |
2 | +<div class='small-loading'> | |
3 | + <%= t('views.cycle._products_loading') %> | |
4 | + | |
5 | + <%= javascript_tag do %> | |
6 | + orders_cycle.cycle.products.load_url = <%= url_for(:action => :products_load, :id => @cycle.id).to_json %> | |
7 | + orders_cycle.cycle.products.load() | |
8 | + <% end %> | |
9 | +</div> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_purchases.html.slim
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_receipts.html.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_results.html.erb
0 → 100644
... | ... | @@ -0,0 +1,9 @@ |
1 | +<% if @closed_cycles.blank? %> | |
2 | + <div class="subtitle"><%= t('views.cycle._results.no_cycles_to_show') %></div> | |
3 | +<% else %> | |
4 | + <% @closed_cycles.each do |cycle| %> | |
5 | + <div id="cycle-<%= cycle.id %>" class="cycle"> | |
6 | + <%= render 'header', :cycle => cycle, :timeline => true, :actions => false, :listing => true %> | |
7 | + </div> | |
8 | + <% end %> | |
9 | +<% end %> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_separation.html.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_timeline.html.erb
0 → 100644
... | ... | @@ -0,0 +1,43 @@ |
1 | +<% | |
2 | + actions = true if actions.nil? and @admin | |
3 | + listing = false if listing.nil? | |
4 | + view_status = if OrdersCyclePlugin::Cycle::Statuses.index(params[:view]) then params[:view] else cycle.status end | |
5 | + status_text = t("models.cycle.statuses.#{view_status}") | |
6 | +%> | |
7 | + | |
8 | +<div class="cycle-timeline"> | |
9 | + <% OrdersCyclePlugin::Cycle::UserStatuses.each do |status| %> | |
10 | + <% | |
11 | + klass = "cycle-timeline-item #{timeline_class cycle, status, view_status}" | |
12 | + name = t("models.cycle.statuses.#{status}") | |
13 | + %> | |
14 | + | |
15 | + <%= link_to name, params.merge(:action => :edit, :id => cycle.id, :view => status), :class => klass %> | |
16 | + <% end %> | |
17 | +</div> | |
18 | + | |
19 | +<% if listing %> | |
20 | + <div class="dates-brief"> | |
21 | + <div class="date"> | |
22 | + <span class="field-title"><%= t('views.cycle._brief.orders') %></span>  | |
23 | + <span><%= datetime_period_short cycle.start, cycle.finish %></span> | |
24 | + </div> | |
25 | + <div class="date"> | |
26 | + <span class="field-title"><%= t('views.cycle._brief.delivery') %></span>  | |
27 | + <span><%= datetime_period_short cycle.delivery_start, cycle.delivery_finish %></span> | |
28 | + </div> | |
29 | + </div> | |
30 | +<% end %> | |
31 | + | |
32 | +<% if actions %> | |
33 | + <div class="actions-bar"> | |
34 | + <% if cycle.status == view_status and cycle.status != 'closing' %> | |
35 | + <%= link_to t('views.cycle._timeline.close_status') % {:status => status_text}, | |
36 | + {:action => :step, :id => cycle.id, :method => :post}, | |
37 | + {:confirm => t('views.cycle._timeline.are_you_sure_you_want_to_close') % {:status => status_text}, :class => 'action-button'} %> | |
38 | + <% end %> | |
39 | + | |
40 | + <%= render "orders_cycle_plugin_cycle/actions/#{view_status}", :cycle => cycle rescue nil %> | |
41 | + </div> | |
42 | +<% end %> | |
43 | + | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_title.html.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_view_dates.html.slim
0 → 100644
... | ... | @@ -0,0 +1,13 @@ |
1 | +- happening = true if !defined?(happening) or happening.nil? | |
2 | + | |
3 | +table#cycle-dates | |
4 | + tr class="orders-date #{"happening" if happening and cycle.orders?}" | |
5 | + th | |
6 | + strong= t'views.cycle._view_dates.orders' | |
7 | + td= datetime_period_with_day cycle.start, cycle.finish | |
8 | + - if happening and cycle.orders? | |
9 | + td.happening= t'views.cycle._view_dates.happening' | |
10 | + tr.delivery-date | |
11 | + th | |
12 | + strong= t'views.cycle._view_dates.delivery' | |
13 | + td= datetime_period_with_day cycle.delivery_start, cycle.delivery_finish | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_view_header.html.erb
0 → 100644
... | ... | @@ -0,0 +1,14 @@ |
1 | +<div id="cycle-others"> | |
2 | + <% others = (profile.orders_cycles.on_orders - [cycle]) %> | |
3 | + <%= ( others.blank? ? t('views.cycle._view_header.see_also_all') : t('views.cycle._view_header.other_open_cycles_lis') ) % { | |
4 | + list: others.map{ |s| link_to(s.name, '') }.join(t('views.cycle._view_header., ')), | |
5 | + all: link_to(t('views.cycle._view_header.all_orders_cycles'), {controller: :orders_cycle_plugin_order, action: :index}), } %> | |
6 | +</div> | |
7 | + | |
8 | +<div id="cycle-header"> | |
9 | + <h2><%=t('views.cycle._view_header.orders_cycle_cycle') % {cycle: content_tag(:strong, cycle.name_with_code)} %></h2> | |
10 | + | |
11 | + <%= render partial: 'orders_cycle_plugin_cycle/view_dates', locals: {cycle: cycle} %> | |
12 | + | |
13 | + <div class="subtitle"><%= cycle.description %></div> | |
14 | +</div> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_view_products.html.erb
0 → 100644
... | ... | @@ -0,0 +1,14 @@ |
1 | +<div id="cycle-products-for-order"> | |
2 | + <div class="title"> | |
3 | + <h3><%=t('views.cycle._view_products.the_products')%></h3> | |
4 | + </div> | |
5 | + | |
6 | + <%= render partial: "orders_cycle_plugin_shared/filter", locals: {type: :order, cycle: cycle, order: order} %> | |
7 | + | |
8 | + <div id="search-results"> | |
9 | + <%= render partial: "orders_cycle_plugin_order/filter", locals: { | |
10 | + cycle: cycle, order: order, | |
11 | + products_for_order: @products, | |
12 | + } %> | |
13 | + </div> | |
14 | +</div> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/_with_selection_actions.html.slim
0 → 100644
... | ... | @@ -0,0 +1,8 @@ |
1 | +.btn-group | |
2 | + button.btn.btn-default.btn-xs.dropdown-toggle aria-expanded="false" data-toggle="dropdown" type="button" | |
3 | + = t('views.admin.reports.generate') | |
4 | + span.caret | |
5 | + | |
6 | + ul.dropdown-menu role="menu" | |
7 | + li= link_to_function t('views.admin.reports.orders_spreadsheet'), "orders.admin.select.report('#{url_for action: :report_orders, id: @cycle.id, orders_method: orders_method}')" | |
8 | + li= link_to_function t('views.admin.reports.products_spreadsheet'), "orders.admin.select.report('#{url_for action: :report_products, id: @cycle.id, orders_method: orders_method}')" | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/actions/_closed.html.erb
0 → 100644
... | ... | @@ -0,0 +1,4 @@ |
1 | +<% if cycle.status == 'closing' %> | |
2 | + <%= link_to t('views.cycle._timeline.reopen_orders_period'), {action: :step_back, id: cycle.id, method: :post}, | |
3 | + {id: 'cycle-open-cycle' , confirm: t('views.cycle._timeline.are_you_sure_you_want_to_reopen'), class: 'action-button'} %> | |
4 | +<% end %> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/actions/_orders.html.slim
0 → 100644
... | ... | @@ -0,0 +1,8 @@ |
1 | +.btn-group | |
2 | + button.btn.btn-default.btn-xs.dropdown-toggle aria-expanded="false" data-toggle="dropdown" type="button" | |
3 | + = t('views.admin.reports.generate') | |
4 | + span.caret | |
5 | + | |
6 | + ul.dropdown-menu role="menu" | |
7 | + li= link_to t('views.admin.reports.orders_spreadsheet'), {action: :report_orders, id: cycle.id} | |
8 | + li= link_to t('views.admin.reports.products_spreadsheet'), {action: :report_products, id: cycle.id} | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/edit.html.erb
0 → 100644
... | ... | @@ -0,0 +1,11 @@ |
1 | +<div id="cycle-admin-page" class='admin-page'> | |
2 | + | |
3 | + <div id="cycle-<%= @cycle.id %>" class="cycle"> | |
4 | + <%= render 'header', :cycle => @cycle, :timeline => true, :actions => true, :listing => false %> | |
5 | + | |
6 | + <% view = if params[:view] then params[:view] else @cycle.status end %> | |
7 | + <div> | |
8 | + <%= render view %> | |
9 | + </div> | |
10 | + </div> | |
11 | +</div> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/edit.js.erb
0 → 100644
... | ... | @@ -0,0 +1,9 @@ |
1 | +<% if params[:commit] %> | |
2 | + <% if @success and @open %> | |
3 | + window.location = <%= url_for(:action => :edit, :id => @cycle.id).to_json %> | |
4 | + <% else %> | |
5 | + noosfero.modal.html(<%= render('edit_popin', :cycle => @cycle).to_json %>) | |
6 | + <% end %> | |
7 | +<% else %> | |
8 | + jQuery("#cycle-products .table").replaceWith('<%= escape_javascript render('product_lines') %>') | |
9 | +<% end %> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/index.html.erb
0 → 100644
... | ... | @@ -0,0 +1,32 @@ |
1 | +<% cycles = @open_cycles %> | |
2 | + | |
3 | +<div id="cycle-listing" class='admin-page'> | |
4 | + <h2><%= t('views.cycle.index.orders_cycles') %></h2> | |
5 | + | |
6 | + <%= link_to t('views.cycle.index.new_cycle'), {:action => :new}, :class => 'cycle-new' %> | |
7 | + | |
8 | + <div id="cycle-open-listing"> | |
9 | + <h3><%= t('views.cycle.index.open_cycles') %></h3> | |
10 | + | |
11 | + <% if cycles.blank? %> | |
12 | + <div class="subtitle"><%= t('views.cycle.index.no_cycles_to_show') %></div> | |
13 | + <% else %> | |
14 | + <% cycles.each do |cycle| %> | |
15 | + <div id="cycle-<%= cycle.id %>" class="cycle cycle-list-item"> | |
16 | + <%= render 'header', :cycle => cycle, :timeline => true, :actions => false, :listing => true %> | |
17 | + </div> | |
18 | + <% end %> | |
19 | + <% end %> | |
20 | + </div> | |
21 | + | |
22 | + <div id="cycle-closed-listing"> | |
23 | + <h3><%= t('views.cycle.index.closed_cycles') %></h3> | |
24 | + | |
25 | + <%= render "orders_cycle_plugin_shared/filter", :type => :orders_cycle, :wireframe_size => true %> | |
26 | + | |
27 | + <div id="search-results"> | |
28 | + <%= render 'results' %> | |
29 | + </div> | |
30 | + </div> | |
31 | + | |
32 | +</div> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_cycle/new.html.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/new.js.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/orders_filter.js.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_cycle/report_products.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_gadgets/_cycle.html.erb
0 → 100644
... | ... | @@ -0,0 +1,25 @@ |
1 | +<div class="cycle"> | |
2 | + <div class='happening'><%= t('views.gadgets._cycle.happening') %></div> | |
3 | + <div class='info'> | |
4 | + <h2> | |
5 | + <%= t('views.gadgets._cycle.orders_open_b_cycle') % {:cycle => cycle.name_with_code} %> | |
6 | + </h2> | |
7 | + | |
8 | + <table> | |
9 | + <tr> | |
10 | + <td class='first-column'> | |
11 | + <%= render :partial => 'orders_cycle_plugin_cycle/view_dates', | |
12 | + :locals => {:cycle => cycle, :happening => false} %> | |
13 | + </td> | |
14 | + <td class='second-column'> | |
15 | + <div class="subtitle"><%= cycle.description %></div> | |
16 | + </td> | |
17 | + <td class='third-column'> | |
18 | + <%= button_to t('views.gadgets._cycle.see_orders_cycle'), {:controller => :orders_cycle_plugin_order, :action => :edit, :cycle_id => cycle.id}, :class => "action-button" %> | |
19 | + <%# button_to t('views.gadgets._cycle.place_an_order'), {:controller => :orders_cycle_plugin_order, :action => :new, :cycle_id => cycle.id} %> | |
20 | + <div class='clean'></div> | |
21 | + </td> | |
22 | + <tr> | |
23 | + </table> | |
24 | + </div> | |
25 | +</div> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_gadgets/cycles.html.erb
0 → 100644
... | ... | @@ -0,0 +1,12 @@ |
1 | +<% extend OrdersCyclePlugin::TranslationHelper %> | |
2 | + | |
3 | +<div id="cycles-gadget"> | |
4 | + <% profile.orders_cycles.on_orders.each do |cycle| %> | |
5 | + <%= render :partial => 'orders_cycle_plugin_gadgets/cycle', :locals => {:cycle => cycle} %> | |
6 | + <% end %> | |
7 | + | |
8 | + <div> | |
9 | + <%= link_to t('views.gadgets.cycles.all_cycles'), {:controller => :orders_cycle_plugin_order, :profile => profile.identifier, :action => :index}, :id => "all-cycles" %> | |
10 | + <div class='clean'></div> | |
11 | + </div> | |
12 | +</div> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_item/_edit.html.erb
0 → 120000
plugins/orders_cycle/views/orders_cycle_plugin_item/_index.html.slim
0 → 120000
plugins/orders_cycle/views/orders_cycle_plugin_item/_price_total.html.erb
0 → 120000
plugins/orders_cycle/views/orders_cycle_plugin_item/_quantity_price.html.slim
0 → 120000
plugins/orders_cycle/views/orders_cycle_plugin_item/destroy.js.erb
0 → 100644
plugins/orders_cycle/views/orders_cycle_plugin_item/new.js.erb
0 → 100644
... | ... | @@ -0,0 +1,10 @@ |
1 | +<% unless params[:redirect] == '1' %> | |
2 | + orders_cycle.order.product.load(<%= @offered_product.id %>, true); | |
3 | + | |
4 | + $('#consumer-order-<%=@order.id%>').html(<%= render('orders_cycle_plugin_order/active_order', order: @order, actor_name: @actor_name).to_json %>); | |
5 | + | |
6 | + var item = $('#item-<%=@item.id%>'); | |
7 | + orders.item.edit_quantity(item); | |
8 | +<% else %> | |
9 | + window.location = <%= url_for(controller: :orders_cycle_plugin_order, action: :edit, id: @order.id).to_json %> | |
10 | +<% end %> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_order/_active_order.html.erb
0 → 100644
... | ... | @@ -0,0 +1,35 @@ |
1 | +<% content_for :order_header do %> | |
2 | + <%= render 'orders_cycle_plugin_order/status', order: @order %> | |
3 | + | |
4 | + <% unless @order.open? %> | |
5 | + <div id="order-status-message" class="order-message status-<%= @order.current_status %>"> | |
6 | + <div class="order-message-text"> | |
7 | + <% if @order.confirmed? %> | |
8 | + <%= t('views.order._consumer_orders.your_order_is_confirm') %> | |
9 | + <% elsif @order.cancelled? %> | |
10 | + <%= t('views.order._consumer_orders.your_order_was_cancel') %> | |
11 | + <% else %> | |
12 | + <%= t('views.order._consumer_orders.your_order_wasn_t_con') %> | |
13 | + <% end %> | |
14 | + </div> | |
15 | + <div class="order-message-actions"> | |
16 | + <div><%= t('views.order._consumer_orders.you_still_can') %></div> | |
17 | + | |
18 | + <% if @order.cycle.orders? %> | |
19 | + <%= link_to_function t('views.order._consumer_orders.change_order'), "orders.order.reload(this, '#{url_for controller: :orders_cycle_plugin_order, action: :reopen, id: @order.id}')" %> | |
20 | + <%= t('views.order._consumer_orders.before_the_closing') %>  | |
21 | + <% end %> | |
22 | + <br> | |
23 | + | |
24 | + <% unless @order.cancelled? %> | |
25 | + <%= link_to_function t('views.order._show.cancel_order'), "orders.order.reload(this, '#{url_for controller: :orders_cycle_plugin_order, action: :cancel, id: @order.id}')" %> | |
26 | + <br> | |
27 | + <% end %> | |
28 | + | |
29 | + <%= modal_link_to t('views.order._consumer_orders.send_message_to_the_m'), {controller: :orders_plugin_message, action: :new_to_admins} %> | |
30 | + </div> | |
31 | + </div> | |
32 | + <% end %> | |
33 | +<% end %> | |
34 | + | |
35 | +<%= render 'orders_plugin_order/show', order: @order, actor_name: :consumer %> | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_order/_consumer_orders.html.slim
0 → 100644
... | ... | @@ -0,0 +1,69 @@ |
1 | += content_for :head do | |
2 | + / while we are not responsive | |
3 | + = stylesheet_link_tag '/assets/designs/icons/awesome/scss/font-awesome.css' | |
4 | + | |
5 | +h3 | |
6 | + - if @admin_edit | |
7 | + = t('views.order._consumer_orders.orders_from_consumer_') % {consumer: @consumer.name} | |
8 | + - elsif @consumer and @cycle.orders? | |
9 | + = t('views.order._consumer_orders.your_orders_on_this_c') | |
10 | + - if @consumer.in? @cycle.profile.members | |
11 | + = link_to t('views.order._consumer_orders.new_order'), {action: :new, cycle_id: @cycle.id}, | |
12 | + class: 'btn btn-default btn-danger fa fa-plus', onclick: "$(this).attr('disabled', '')" | |
13 | + - if not @admin_edit and @cycle.consumer_previous_orders(@consumer).present? | |
14 | + = link_to t('views.order._consumer_orders.repeat_order'), {action: :repeat, cycle_id: @cycle.id}, | |
15 | + class: 'modal-toggle btn btn-default btn-danger fa fa-repeat' | |
16 | + | |
17 | +- if @order and @order.consumer != @consumer and @admin_edit | |
18 | + #order-admin-warning.order-message | |
19 | + .order-message-text | |
20 | + = t'views.order._consumer_orders.caution', consumer: @consumer.name | |
21 | + .order-message-actions | |
22 | + = link_to t('views.order._consumer_orders.edit_your_orders'), {action: :edit, cycle_id: @cycle.id} | |
23 | + |  | |
24 | + = link_to t('views.order._consumer_orders.administration_of_thi'), {controller: :orders_cycle_plugin_cycle, action: :edit, id: @cycle.id} | |
25 | + |  | |
26 | + #order-place-new.admin | |
27 | + = link_to t('views.order._consumer_orders.new_order'), {action: :admin_new, consumer_id: @order.consumer.id, cycle_id: @cycle.id} if @cycle.orders? | |
28 | +- else | |
29 | + - if @consumer.nil? | |
30 | + - message = t'views.order._consumer_orders.to_place_an_order_you', | |
31 | + login: modal_link_to(t('views.order._consumer_orders.login'), login_url, id: 'link_login'), | |
32 | + signup: link_to(t('views.order._consumer_orders.sign_up'), controller: 'account', action: 'signup') | |
33 | + - else | |
34 | + - if @cycle.orders? | |
35 | + - if not @admin and not @consumer.in? @cycle.profile.members and @cycle.profile.community? | |
36 | + = t'views.order._consumer_orders.associate_to_order' | |
37 | + = render 'blocks/profile_info_actions/join_leave_community' | |
38 | + - elsif @consumer_orders.count == 0 | |
39 | + - message = t'views.order._consumer_orders.you_haven_t_placed_an' | |
40 | + - elsif @cycle.edition? | |
41 | + - message = t'views.order._consumer_orders.this_cycle_is_not_ope' | |
42 | + - elsif @cycle.before_orders? | |
43 | + - message = t'views.order._consumer_orders.the_time_for_orders_is', start: l(@cycle.start, format: :short), finish: l(@cycle.finish, format: :short) | |
44 | + - elsif @cycle.after_orders? | |
45 | + - message = t'views.order._consumer_orders.this_cycle_is_already' | |
46 | + - if message | |
47 | + #order-place-new | |
48 | + = message | |
49 | +.clean | |
50 | + | |
51 | +- @consumer_orders.each do |order| | |
52 | + - if @order != order and order.current_status == 'cancelled' | |
53 | + #show-cancelled-orders | |
54 | + = link_to_function t('views.order._consumer_orders.show_cancelled_orders'), "orders_cycle.toggleCancelledOrders()" | |
55 | + #hide-cancelled-orders | |
56 | + = link_to_function t('views.order._consumer_orders.hide_cancelled_orders'), "orders_cycle.toggleCancelledOrders()", style: 'display:none' | |
57 | + - break | |
58 | +- @consumer_orders.each do |order| | |
59 | + - next if @order == order | |
60 | + div class=("consumer-order unactive #{order.current_status}") id="consumer-order-#{order.id}" | |
61 | + = render 'status', order: order | |
62 | + .actions | |
63 | + = link_to t('views.order._show.open'), {action: :edit, id: order.id} | |
64 | + .clean | |
65 | + | |
66 | +/ prints out the referenced order | |
67 | +- if @order | |
68 | + .consumer-order.edit.active-order id="consumer-order-#{@order.id}" | |
69 | + = render 'orders_cycle_plugin_order/active_order' | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_order/_filter.html.slim
0 → 100644
... | ... | @@ -0,0 +1,43 @@ |
1 | +- draft_order = cycle.sales.draft.for_consumer(user).first | |
2 | +- include_message = '' | |
3 | +- if order.nil? | |
4 | + - if draft_order | |
5 | + - order_id = draft_order.id | |
6 | + - include_message = t'orders_cycle_plugin.views.product._order_edit.opening_order_code_fo', code: draft_order.code | |
7 | + - elsif cycle.may_order? user | |
8 | + - order_id = 'new' | |
9 | + - include_message = t'orders_cycle_plugin.views.product._order_edit.opening_new_order_for' | |
10 | +- else | |
11 | + - order_id = order.id | |
12 | +- editable = (order.present? && order.may_edit?(user, @admin)) || order_id == 'new' | |
13 | + | |
14 | +- if products_for_order.empty? | |
15 | + strong= t'orders_cycle_plugin.views.product._order_search.this_search_hasn_t_re' | |
16 | +- else | |
17 | + #cycle-products.sortable-table | |
18 | + .table-header | |
19 | + .box-field.category= t'orders_cycle_plugin.views.product._order_search.category' | |
20 | + .box-field.supplier= t'orders_cycle_plugin.views.product._order_search.producer' | |
21 | + .box-field.product= t'orders_cycle_plugin.views.product._order_search.product' | |
22 | + .box-field.price-with-unit= t'orders_cycle_plugin.views.product._order_search.price' | |
23 | + .table-content | |
24 | + - products_for_order.each do |offered_product| | |
25 | + - next if offered_product.supplier.nil? | |
26 | + div class=("order-cycle-product value-row #{'editable' if editable}") id="cycle-product-#{offered_product.id}" onclick="orders_cycle.order.product.click(event, #{offered_product.id.to_json});" supplier-id="#{offered_product.supplier.id}" toggle-ignore="" | |
27 | + - item = if order.blank? then nil else order.items.find{ |op| offered_product.id == op.product_id } end | |
28 | + = render 'orders_cycle_plugin_product/order_edit', editable: editable, | |
29 | + product: offered_product, order: order, cycle: cycle, item: item | |
30 | + | |
31 | + = pagination_links products_for_order, params: {action: :edit, controller: :orders_cycle_plugin_order, cycle_id: cycle.id, order_id: order_id}, | |
32 | + class: 'pagination infinite-scroll' | |
33 | + | |
34 | +javascript: | |
35 | + orders_cycle.order.load() | |
36 | + orders_cycle.order.product.include_message = '#{include_message}' | |
37 | + orders_cycle.order.product.order_id = #{order_id.to_json} | |
38 | + orders_cycle.order.product.redirect_after_include = '#{order.nil? ? 1 : ''}' | |
39 | + orders_cycle.order.product.add_url = '#{url_for controller: :orders_cycle_plugin_item, action: :new}' | |
40 | + orders_cycle.order.product.remove_url = '#{url_for controller: :orders_cycle_plugin_product, action: :remove_from_order}' | |
41 | + orders_cycle.order.product.balloon_url = '#{url_for controller: :orders_cycle_plugin_order, action: :product_balloon}' | |
42 | + orders_cycle.order.product.supplier.balloon_url = '#{url_for controller: :orders_cycle_plugin_order, action: :supplier_balloon}' | |
43 | + pagination.infiniteScroll(#{_('loading...').to_json}, {load: orders_cycle.order.product.showMore}) | ... | ... |
plugins/orders_cycle/views/orders_cycle_plugin_order/_filter_fields.html.slim
0 → 100644
... | ... | @@ -0,0 +1,23 @@ |
1 | += hidden_field_tag :cycle_id, cycle.id | |
2 | += hidden_field_tag :order_id, order.id unless order.nil? | |
3 | + | |
4 | +.field.supplier | |
5 | + label= t'orders_cycle_plugin.views.order._filter_products.supplier' | |
6 | + div= select_tag :supplier_id, | |
7 | + options_for_select([[t('orders_cycle_plugin.views.order._filter_products.all_the_suppliers'), ""]] + supplier_choices(cycle.suppliers), params[:supplier_profile_id].to_i) | |
8 | + | |
9 | +.field.category | |
10 | + label= t'suppliers_plugin.views.product.index.category' | |
11 | + div | |
12 | + = select_tag :category_id, options_for_select(@product_categories.map{ |pc| [pc.name, pc.id]}.insert(0,[t('suppliers_plugin.views.product.index.all_the_categories'), ""])) | |
13 | + | |
14 | +/.field.qualifier | |
15 | + div= select_tag :qualifier_id, options_for_select([t('orders_cycle_plugin.views.order._filter_products.anyone'), '']) | |
16 | + | |
17 | +/.field.stock | |
18 | + div= t'orders_cycle_plugin.views.order._filter_products.whose_qty_available_i') | |
19 | + div= select_tag :stock, options_for_select([t('orders_cycle_plugin.views.order._filter_products.bigger_than_the_stock'), '']) | |
20 | + | |
21 | +.field.name | |
22 | + label= t'orders_cycle_plugin.views.order._filter_products.product_name' | |
23 | + div= text_field_tag :name, params[:name] | ... | ... |