educode_sales 0.9.84 → 0.9.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e498fa041334cb4b387425a7a7f7ff49dffffcee5a72e363b61cb9f32167ff06
4
- data.tar.gz: 54d79d72be99cab109f9b40fdd4dd789f72f20d115663abd7d99db70f0ee2527
3
+ metadata.gz: 85457062bb8c20c8e1703353efcb1f958eb39d5e15ca0936efac9f58ca720184
4
+ data.tar.gz: f115e02bf7cdfc392673bf27c533fd6d6cbb87a462936708eb3d1e8e093607f4
5
5
  SHA512:
6
- metadata.gz: 1e29ad8d3c8dd8c0753dc6662e26c332444cbf10842d308977883c47149c676b0b1c06c515bcfc33e10fe0bfccbc1cecb5ab1c7f2534001c0c1d7a11042a5def
7
- data.tar.gz: 5077f36f7bb732c196608fd15c696c06b3d0cf5c74e32c24495b67eadc8b5527eacb1a545966aeea4e3401410ed0e1fbe23c2fb60aea58a8b5513fd1fd570ba6
6
+ metadata.gz: 0d0b2b9d028276ee69d72a5e480772c4676c341c8390c6bdfad9880bb9b303f8ab004c9ca2b52f44a9b0bf20e6d259a5973bb0fa83f022b4fa23cb96f27ac581
7
+ data.tar.gz: 2ee2104f1259feac76bc7d562616e266cce1488d5785e5383158dab5450799b7d3436822f29d57d3ae9f3c7044fb94815f3dec0450890ea6a1ef0db2451359af
@@ -454,6 +454,24 @@ module EducodeSales
454
454
  render layout: false
455
455
  end
456
456
 
457
+ def new_sales_detail
458
+ render layout: false
459
+ end
460
+
461
+ def select_product
462
+ render layout: false
463
+ end
464
+
465
+ def sales_detail
466
+ sales_detail = SalesDetail.new(sales_detail_params)
467
+ sales_detail.staff = @current_admin
468
+ if sales_detail.save
469
+ render_success
470
+ else
471
+ render_failure sales_detail
472
+ end
473
+ end
474
+
457
475
  private
458
476
  def follow_up_params
459
477
  params.permit(:o_business_deployment, :plan_signed_date, :bidded_days, :signed_date, :signed_department_id, :service_years, :service_start_time, :service_end_time, :funding_source, :signed_clazz)
@@ -462,5 +480,10 @@ module EducodeSales
462
480
  def product_up_params
463
481
  params.permit(:name, :item_clazz, :brand, :specification, :unit, :param, :source_method, :supplier)
464
482
  end
483
+
484
+ def sales_detail_params
485
+ params.permit(:amount, :price, :total_price, :custom_clazz, :delivery_date, :product_catalog_id, :business_id)
486
+ end
487
+
465
488
  end
466
489
  end
@@ -2,5 +2,140 @@ require_dependency "educode_sales/application_controller"
2
2
 
3
3
  module EducodeSales
4
4
  class SalesDetailsController < ApplicationController
5
+
6
+ def index
7
+ respond_to do |format|
8
+ format.html do
9
+ common = Common.find_by(clazz: 'staff_type', name: '销售')
10
+ staffs = Staff.joins(:user).where(job_type: common.id).where.not(role_id: 11)
11
+ @staffs = staffs.map { |d| [d.user.real_name, d.id]}
12
+ gon.place = params[:place_id].present? ? [{ value: params[:place_id], name: EducodeSales::Place.find(params[:place_id]).name }] : []
13
+ gon.staffs = staffs.map { |d| {name: d.user.real_name, value: d.id } }
14
+
15
+ bussiness_type = []
16
+ if params[:type]
17
+ # 项目类型
18
+ bussiness_type = EducodeSales::Business.include_types(params[:type]) || []
19
+ end
20
+
21
+ business_step = []
22
+ if params[:step]
23
+ # 项目阶段
24
+ business_step = EducodeSales::Business.include_steps(params[:step]) || []
25
+ end
26
+
27
+
28
+ gon.business_type = Common.where(clazz: 'business_type').map do |d|
29
+ {value: d.id, name: d.name, selected: bussiness_type.include?(d.extras)}
30
+ end
31
+
32
+ gon.business_step = Common.where(clazz: 'business_step', name: ['已中标', '已签单', '已验收', '回款中', '服务中', '已结束']).order("position").map do |d|
33
+ {value: d.id, name: d.name, selected: business_step.include?(d.name)}
34
+ end
35
+ end
36
+ format.json do
37
+ @sales_details = SalesDetail
38
+ @sales_details = @sales_details.joins(:business).includes(:business, :product_catalog)
39
+
40
+ if params[:q] && params[:q][:signed_date].present?
41
+ date = params[:q][:signed_date].split(" - ")
42
+ @sales_details = @sales_details.joins("
43
+ JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id
44
+ ").where("educode_sales_follow_ups.signed_date >= ? AND educode_sales_follow_ups.signed_date <= ?", date[0], date[1])
45
+ end
46
+
47
+ if params[:q] && params[:q][:bidded_date].present?
48
+ date = params[:q][:bidded_date].split(" - ")
49
+ @sales_details = @sales_details.joins("
50
+ JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id
51
+ ").where("educode_sales_follow_ups.bidded_date >= ? AND educode_sales_follow_ups.bidded_date <= ?", date[0], date[1])
52
+ end
53
+
54
+ if params[:q].present? && params[:q][:name].present?
55
+ @sales_details = @sales_details.where("educode_sales_businesses.name like ?", "%#{params[:q][:name]}%")
56
+ end
57
+
58
+ if params[:sort].present? && params[:sort][:field]
59
+ @sales_details = @sales_details.order("#{params[:sort][:field]} #{params[:sort][:order]}")
60
+ else
61
+ @sales_details = @sales_details.order("educode_sales_sales_details.created_at desc")
62
+ end
63
+
64
+ if params[:q].present? && params[:q][:business_step].present?
65
+ @sales_details = @sales_details.joins("
66
+ JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id
67
+ ").where("educode_sales_follow_ups.stage_id in (?)", params[:q][:business_step].split(",").map(&:to_i))
68
+ end
69
+
70
+
71
+ if params[:q].present? && params[:q][:sales_staff_id].present?
72
+ # 销售经理
73
+ @sales_details = @sales_details.joins("LEFT JOIN educode_sales_assign_follow_ups ON educode_sales_assign_follow_ups.follow_up_id = educode_sales_businesses.last_follow_up_id").
74
+ where("(educode_sales_assign_follow_ups.id IS NOT NULL AND educode_sales_assign_follow_ups.staff_id = ?) OR (educode_sales_assign_follow_ups.id IS NULL AND educode_sales_businesses.staff_id = ?)", params[:q][:sales_staff_id], params[:q][:sales_staff_id])
75
+
76
+ end
77
+
78
+ if params[:q].present? && params[:q][:department].present?
79
+ departments_ids = Department.joins(:school).where("schools.name like ?", "%#{params[:q][:department]}%").pluck(:id)
80
+ @sales_details = @sales_details.joins(business: :department).where("departments.id in (?)", departments_ids)
81
+ end
82
+
83
+ if params[:q].present? && params[:q][:area].present?
84
+ area = EducodeSales::Common.find(params[:q][:area]).name
85
+ if @current_admin.is_admin?
86
+ @sales_details = @sales_details.joins("
87
+ JOIN departments ON educode_sales_businesses.department_id = departments.id
88
+ JOIN schools ON departments.school_id = schools.id
89
+ ").where("province = ?", area)
90
+ else
91
+ level = @current_admin.role.role_areas.find_by(clazz: '商机管理').level
92
+ if level == "区域"
93
+ @sales_details = @sales_details.joins("
94
+ JOIN schools ON departments.school_id = schools.id
95
+ ").where("province = ?", area)
96
+ else
97
+ @sales_details = @sales_details.joins("
98
+ JOIN departments ON educode_sales_businesses.department_id = departments.id
99
+ JOIN schools ON departments.school_id = schools.id
100
+ ").where("province = ?", area)
101
+ end
102
+ end
103
+ end
104
+
105
+ @sales_details = @sales_details.page(params[:page]).per(params[:limit])
106
+ end
107
+ end
108
+ end
109
+
110
+ def destroy
111
+ sales_detail = SalesDetail.find(params[:id])
112
+ if sales_detail.destroy
113
+ render_success
114
+ else
115
+ render_failure sales_detail
116
+ end
117
+ end
118
+
119
+ def edit
120
+ @sale_detail = SalesDetail.find(params[:id])
121
+ @name = [@sale_detail.business.name, @sale_detail.product_catalog.item_clazz, @sale_detail.product_catalog.brand, @sale_detail.product_catalog.specification, @sale_detail.product_catalog.unit, @sale_detail.product_catalog.source_method, @sale_detail.product_catalog.param, @sale_detail.product_catalog.supplier].join(" ")
122
+ render layout: false
123
+ end
124
+
125
+ def update
126
+ sale_detail = SalesDetail.find(params[:id])
127
+ if sale_detail.update(sales_detail_params)
128
+ render_success
129
+ else
130
+ render_failure sale_detail
131
+ end
132
+ end
133
+
134
+ private
135
+
136
+ def sales_detail_params
137
+ params.permit(:amount, :price, :total_price, :custom_clazz, :delivery_date, :product_catalog_id)
138
+ end
139
+
5
140
  end
6
141
  end
@@ -3,5 +3,6 @@ module EducodeSales
3
3
  belongs_to :business
4
4
  belongs_to :product_catalog
5
5
  belongs_to :staff
6
+ enum custom_clazz: ['非定制', '低定制', '高定制', '全定制']
6
7
  end
7
8
  end
@@ -110,6 +110,7 @@
110
110
  <% if can? :assign_contract, EducodeSales::Business %>
111
111
  <a class="layui-btn layui-btn-default layui-btn-xs data-count-edit" lay-event="assign">指派售后</a>
112
112
  <% end %>
113
+ <a class="layui-btn layui-btn-default layui-btn-xs data-count-edit" lay-event="add_sales">添加销售明细</a>
113
114
 
114
115
  </script>
115
116
 
@@ -431,7 +432,7 @@
431
432
  },
432
433
  {
433
434
  title: '操作',
434
- minWidth: 220,
435
+ minWidth: 300,
435
436
  toolbar: '#currentTableBar',
436
437
  align: "center",
437
438
  fixed: 'right'
@@ -546,6 +547,26 @@
546
547
  layer.full(sindex);
547
548
  });
548
549
  return false;
550
+ } else if (obj.event === 'add_sales') {
551
+ business_id = data.id
552
+ var content = miniPage.getHrefContent('/missions/contracts/new_sales_detail?id=' + data.id);
553
+ var openWH = miniPage.getOpenWidthHeight();
554
+ new_sale_index = layer.open({
555
+ title: '添加销售明细',
556
+ type: 1,
557
+ shade: 0.2,
558
+ maxmin: true,
559
+ shadeClose: true,
560
+ area: [openWH[0] + 'px', openWH[1] + 'px'],
561
+ offset: [openWH[2] + 'px', openWH[3] + 'px'],
562
+ content: content,
563
+ success: function (layero, index) {
564
+ form.render('select');
565
+ }
566
+ });
567
+ $(window).on("resize", function () {
568
+ layer.full(new_follow_index);
569
+ });
549
570
  }
550
571
  });
551
572
 
@@ -120,7 +120,7 @@
120
120
  </div>
121
121
  </div>
122
122
  <div class="layui-inline">
123
- <label class="layui-form-label">签约类型:</label>
123
+ <label class="layui-form-label">签单类型:</label>
124
124
  <div class="layui-input-inline" style="line-height: 38px;width:110px;">
125
125
  <%= select_tag "signed_clazz", options_for_select(@signed_clazz, @last_follow_up&.signed_clazz), class: 'required' %>
126
126
  </div>
@@ -0,0 +1,116 @@
1
+ <%= Gon::Base.render_data %>
2
+ <div style="padding:30px">
3
+ <div class="layui-form layuimini-form" lay-filter="searchform">
4
+ <div class="layui-form-item">
5
+ <div class="layui-inline">
6
+ <label class="layui-form-label">产品名称:</label>
7
+ <div class="layui-input-inline" style="line-height: 38px;width: 400px;" id="product_name">
8
+ </div>
9
+ <div class="layui-form-mid layui-text-em"><button class="layui-btn layui-btn-sm" id="open_product">选择产品</button></div>
10
+ <input type="hidden" name="product_catalog_id" id="product_catalog_id">
11
+ </div>
12
+ </div>
13
+ <div class="layui-form-item">
14
+ <div class="layui-inline">
15
+ <label class="layui-form-label required">单价:</label>
16
+ <div class="layui-input-inline">
17
+ <input type="number" name="price" value="" class="layui-input" lay-verify="required">
18
+ </div>
19
+ </div>
20
+ <div class="layui-inline">
21
+ <label class="layui-form-label required">数量:</label>
22
+ <div class="layui-input-inline">
23
+ <input type="number" name="amount" value="" class="layui-input" lay-verify="required">
24
+ </div>
25
+ </div>
26
+ <div class="layui-inline">
27
+ <label class="layui-form-label required">金额:</label>
28
+ <div class="layui-input-inline">
29
+ <input type="number" name="total_price" value="" class="layui-input" lay-verify="required">
30
+ </div>
31
+ </div>
32
+
33
+ </div>
34
+ <div class="layui-form-item">
35
+ <div class="layui-inline">
36
+ <label class="layui-form-label required">定制类型:</label>
37
+ <div class="layui-input-inline">
38
+ <%= select_tag "custom_clazz", options_for_select(EducodeSales::SalesDetail.custom_clazzs.keys), { 'lay-filter': 'source_method', 'lay-verify': "required", include_blank: true, "lay-search": "" } %>
39
+ </div>
40
+ </div>
41
+ <div class="layui-inline">
42
+ <label class="layui-form-label required">交货时间:</label>
43
+ <div class="layui-input-inline">
44
+ <input type="text" name="delivery_date" value="" class="layui-input" lay-verify="required" id="delivery_date">
45
+ </div>
46
+ </div>
47
+ </div>
48
+ <div class="layui-form-item">
49
+ <div class="layui-input-block">
50
+ <button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">保存</button>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <script type="text/html" id="sale_toolbar">
57
+ <div class="layui-btn-container">
58
+ <button class="layui-btn layui-btn-sm" lay-event="select_product">选择产品</button>
59
+ </div>
60
+ </script>
61
+ <script>
62
+ function selectProduct(data) {
63
+ $("#product_catalog_id").val(data.id)
64
+ product_name.innerText = [data.name, data.item_clazz, data.brand, data.specification, data.unit, data.source_method, data.param, data.supplier].join(" ")
65
+ }
66
+ layui.use(['form', 'table', 'upload', 'laytpl', 'request', 'laydate'], function() {
67
+ var form = layui.form,
68
+ layer = layui.layer,
69
+ table = layui.table,
70
+ laydate = layui.laydate,
71
+ laytpl = layui.laytpl,
72
+ request = layui.request,
73
+ $ = layui.$;
74
+ form.render();
75
+
76
+ laydate.render({
77
+ elem: '#delivery_date',
78
+ });
79
+
80
+
81
+ $("#open_product").on("click", function() {
82
+ var content = miniPage.getHrefContent('/missions/contracts/select_product');
83
+ var openWH = miniPage.getOpenWidthHeight();
84
+ product_index = layer.open({
85
+ title: '选择产品',
86
+ type: 1,
87
+ shade: 0.2,
88
+ maxmin: true,
89
+ shadeClose: true,
90
+ area: [openWH[0] + 'px', openWH[1] + 'px'],
91
+ offset: [openWH[2] + 'px', openWH[3] + 'px'],
92
+ content: content,
93
+ success: function (layero, index) {
94
+ form.render('select');
95
+ }
96
+ });
97
+ $(window).on("resize", function () {
98
+ layer.full(new_follow_index);
99
+ });
100
+ })
101
+
102
+ form.on('submit(saveBtn)', function(data) {
103
+ console.log( data.field)
104
+ data.field.business_id = parent.business_id;
105
+ if (data.field.product_catalog_id == "") {
106
+ layer.alert("请选择产品")
107
+ return false;
108
+ }
109
+ request.post("missions/contracts/sales_detail", data.field, function(res) {
110
+ layer.close(parent.new_sale_index)
111
+ // parent.table.reload('add_sale_detail_table')
112
+ })
113
+ return false;
114
+ });
115
+ });
116
+ </script>
@@ -0,0 +1,126 @@
1
+ <div style="padding:30px">
2
+ <div class="layui-form layuimini-form" style="padding:30px" lay-filter="search_product_form">
3
+ <div class="layui-form-item">
4
+ <div class="layui-inline">
5
+ <label class="layui-form-label">产品名称</label>
6
+ <div class="layui-input-inline">
7
+ <input type="text" name="name" class="layui-input" value="">
8
+ </div>
9
+ </div>
10
+ <div class="layui-inline">
11
+ <label class="layui-form-label">销售品目</label>
12
+ <div class="layui-input-inline">
13
+ <%= select_tag "item_clazz", options_for_select(EducodeSales::ProductCatalog.item_clazzs.keys), { 'lay-filter': 'item_clazz', include_blank: true , "lay-search": "" } %>
14
+ </div>
15
+ </div>
16
+ <div class="layui-inline">
17
+ <button type="submit" id="search_bt" class="layui-btn layui-btn-primary" lay-submit lay-filter="search_product_catalog_form">搜索</button>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ <div id="sale_detail_table_wraper">
22
+ <table class="layui-hide" id="sale_detail_table" lay-filter="sale_detail_table"></table>
23
+ </div>
24
+ </div>
25
+
26
+ <script type="text/html" id="sale_toolbar">
27
+ <div class="layui-btn-container">
28
+ <button class="layui-btn layui-btn-sm" lay-event="select_product">选择产品</button>
29
+ </div>
30
+ </script>
31
+ <script>
32
+ layui.use(['form', 'table', 'upload', 'laytpl', 'request', 'selectInput'], function() {
33
+ var form = layui.form,
34
+ layer = layui.layer,
35
+ table = layui.table,
36
+ laytpl = layui.laytpl,
37
+ request = layui.request,
38
+ $ = layui.$;
39
+ form.render();
40
+
41
+ var cols_table = [
42
+ [{
43
+ type: 'radio',
44
+ fixed: true
45
+ }, {
46
+ field: 'id',
47
+ width: 60,
48
+ title: '序号',
49
+ }, {
50
+ field: 'name',
51
+ width: 120,
52
+ title: '产品名称',
53
+ }, {
54
+ field: 'item_clazz',
55
+ width: 150,
56
+ title: '销售品目',
57
+ }, {
58
+ field: 'brand',
59
+ width: 150,
60
+ title: '品牌',
61
+ }, {
62
+ field: 'specification',
63
+ width: 150,
64
+ title: '规格型号',
65
+ }, {
66
+ field: 'unit',
67
+ width: 150,
68
+ title: '单位',
69
+ }, {
70
+ field: 'param',
71
+ width: 150,
72
+ title: '参数',
73
+ }, {
74
+ field: 'source_method',
75
+ width: 150,
76
+ title: '来源方式',
77
+ }, {
78
+ field: 'supplier',
79
+ width: 150,
80
+ title: '供货商',
81
+ }, ]
82
+ ]
83
+
84
+ var sale_detail_table = table.render({
85
+ elem: '#sale_detail_table',
86
+ url: '/missions/contracts/product_list',
87
+ autoSort: false,
88
+ title: '销售产品',
89
+ toolbar: '#sale_toolbar',
90
+ cols: cols_table,
91
+ limit: 20,
92
+ limits: [10, 15, 20, 30, 40, 50, 60, 70, 80, 90],
93
+ page: true,
94
+ skin: 'line',
95
+ });
96
+
97
+ form.on('submit(search_product_catalog_form)', function(data) {
98
+ var data = form.val("search_product_form");
99
+ console.log(data)
100
+ table.reload('sale_detail_table', {
101
+ url: '/missions/contracts/product_list',
102
+ page: {
103
+ curr: 1
104
+ },
105
+ where: {
106
+ q: data,
107
+ }
108
+ }, 'data');
109
+ return false;
110
+ });
111
+
112
+ table.on('toolbar(sale_detail_table)', function(obj) {
113
+ var id = obj.config.id;
114
+ if (obj.event == 'select_product') {
115
+ var checkStatus = table.checkStatus(id);
116
+ var row = checkStatus.data;
117
+ if (row[0]) {
118
+ var data = row[0];
119
+ parent.selectProduct(data)
120
+ layer.close(product_index);
121
+ }
122
+ }
123
+ })
124
+
125
+ });
126
+ </script>
@@ -6,7 +6,10 @@
6
6
  <div class="layui-inline m-t-10">
7
7
  <label class="layui-form-label">销售人员</label>
8
8
  <div class="layui-input-inline">
9
- <%= select_tag "staff_id", options_for_select(EducodeSales::Staff.all.includes(:user).map { |d| [d.user.real_name, d.id] }, params[:staff_id]), { 'lay-filter': 'staff_id', include_blank: true } %>
9
+ <% common = EducodeSales::Common.find_by(clazz: 'staff_type', name: '销售')
10
+ staffs = EducodeSales::Staff.where(job_type: common.id)
11
+ %>
12
+ <%= select_tag "staff_id", options_for_select(staffs.includes(:user).map { |d| [d.user.real_name, d.id] }, params[:staff_id]), { 'lay-filter': 'staff_id', include_blank: true } %>
10
13
  </div>
11
14
  </div>
12
15
  <div class="layui-inline m-t-10">
@@ -0,0 +1,115 @@
1
+ <%= Gon::Base.render_data %>
2
+ <div style="padding:30px">
3
+ <div class="layui-form layuimini-form" lay-filter="searchform">
4
+ <div class="layui-form-item">
5
+ <div class="layui-inline">
6
+ <label class="layui-form-label">产品名称:</label>
7
+ <div class="layui-input-inline" style="line-height: 38px;width: 400px;" id="product_name">
8
+ <%= @name %>
9
+ </div>
10
+ <div class="layui-form-mid layui-text-em"><button class="layui-btn layui-btn-sm" id="open_product">选择产品</button></div>
11
+ <input type="hidden" name="product_catalog_id" id="product_catalog_id" value="<%= @sale_detail.product_catalog_id %>">
12
+ </div>
13
+ </div>
14
+ <div class="layui-form-item">
15
+ <div class="layui-inline">
16
+ <label class="layui-form-label required">单价:</label>
17
+ <div class="layui-input-inline">
18
+ <input type="number" name="price" value="<%= @sale_detail.price %>" class="layui-input" lay-verify="required">
19
+ </div>
20
+ </div>
21
+ <div class="layui-inline">
22
+ <label class="layui-form-label required">数量:</label>
23
+ <div class="layui-input-inline">
24
+ <input type="number" name="amount" value="<%= @sale_detail.amount %>" class="layui-input" lay-verify="required">
25
+ </div>
26
+ </div>
27
+ <div class="layui-inline">
28
+ <label class="layui-form-label required">金额:</label>
29
+ <div class="layui-input-inline">
30
+ <input type="number" name="total_price" value="<%= @sale_detail.total_price %>" class="layui-input" lay-verify="required">
31
+ </div>
32
+ </div>
33
+
34
+ </div>
35
+ <div class="layui-form-item">
36
+ <div class="layui-inline">
37
+ <label class="layui-form-label required">定制类型:</label>
38
+ <div class="layui-input-inline">
39
+ <%= select_tag "custom_clazz", options_for_select(EducodeSales::SalesDetail.custom_clazzs.keys, @sale_detail.custom_clazz), { 'lay-filter': 'source_method', 'lay-verify': "required", include_blank: true, "lay-search": "" } %>
40
+ </div>
41
+ </div>
42
+ <div class="layui-inline">
43
+ <label class="layui-form-label required">交货时间:</label>
44
+ <div class="layui-input-inline">
45
+ <input type="text" name="delivery_date" value="<%= @sale_detail.delivery_date %>" class="layui-input" lay-verify="required" id="delivery_date">
46
+ </div>
47
+ </div>
48
+ </div>
49
+ <div class="layui-form-item">
50
+ <div class="layui-input-block">
51
+ <button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">保存</button>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </div>
56
+
57
+ <script type="text/html" id="sale_toolbar">
58
+ <div class="layui-btn-container">
59
+ <button class="layui-btn layui-btn-sm" lay-event="select_product">选择产品</button>
60
+ </div>
61
+ </script>
62
+ <script>
63
+ function selectProduct(data) {
64
+ $("#product_catalog_id").val(data.id)
65
+ product_name.innerText = [data.name, data.item_clazz, data.brand, data.specification, data.unit, data.source_method, data.param, data.supplier].join(" ")
66
+ }
67
+ layui.use(['form', 'table', 'upload', 'laytpl', 'request', 'laydate'], function() {
68
+ var form = layui.form,
69
+ layer = layui.layer,
70
+ table = layui.table,
71
+ laydate = layui.laydate,
72
+ laytpl = layui.laytpl,
73
+ request = layui.request,
74
+ $ = layui.$;
75
+ form.render();
76
+
77
+ laydate.render({
78
+ elem: '#delivery_date',
79
+ });
80
+
81
+
82
+ $("#open_product").on("click", function() {
83
+ var content = miniPage.getHrefContent('/missions/contracts/select_product');
84
+ var openWH = miniPage.getOpenWidthHeight();
85
+ product_index = layer.open({
86
+ title: '选择产品',
87
+ type: 1,
88
+ shade: 0.2,
89
+ maxmin: true,
90
+ shadeClose: true,
91
+ area: [openWH[0] + 'px', openWH[1] + 'px'],
92
+ offset: [openWH[2] + 'px', openWH[3] + 'px'],
93
+ content: content,
94
+ success: function (layero, index) {
95
+ form.render('select');
96
+ }
97
+ });
98
+ $(window).on("resize", function () {
99
+ layer.full(new_follow_index);
100
+ });
101
+ })
102
+
103
+ form.on('submit(saveBtn)', function(data) {
104
+ if (data.field.product_catalog_id == "") {
105
+ layer.alert("请选择产品")
106
+ return false;
107
+ }
108
+ request.put("missions/sales_details/" + parent.id, data.field, function(res) {
109
+ layer.close(parent.sindex)
110
+ parent.table.reload('sales_details_table')
111
+ })
112
+ return false;
113
+ });
114
+ });
115
+ </script>
@@ -0,0 +1,401 @@
1
+ <div class="min-height-table" id="contract_list">
2
+ <div style="margin: 10px 10px 10px 10px">
3
+ <form class="layui-form layui-form-pane" lay-filter="search_form">
4
+ <div class="layui-form-item">
5
+ <div class="layui-inline">
6
+ <label class="layui-form-label">合同名称</label>
7
+ <div class="layui-input-inline">
8
+ <input type="text" name="name" class="layui-input" value="">
9
+ </div>
10
+ </div>
11
+ <div class="layui-inline">
12
+ <label class="layui-form-label">用户单位</label>
13
+ <div class="layui-input-inline">
14
+ <input type="text" name="department" class="layui-input">
15
+ </div>
16
+ </div>
17
+ <div class="layui-inline">
18
+ <label class="layui-form-label">签约单位</label>
19
+ <div class="layui-input-inline">
20
+ <input type="text" name="signed_department" class="layui-input">
21
+ </div>
22
+ </div>
23
+ <div class="layui-inline">
24
+ <label class="layui-form-label">销售经理</label>
25
+ <div class="layui-input-inline">
26
+ <%= select_tag "sales_staff_id", options_for_select(@staffs, params[:staff_id]), { 'lay-filter': 'staff_id', include_blank: true , "lay-search": "" } %>
27
+ </div>
28
+ </div>
29
+
30
+ <div class="layui-inline show_item_contract">
31
+ <label class="layui-form-label">项目阶段</label>
32
+ <div class="layui-input-inline">
33
+ <div id="contract_business_step" style="width: 190px;"></div>
34
+ </div>
35
+ </div>
36
+ <div class="layui-inline show_item_contract">
37
+ <label class="layui-form-label">区域</label>
38
+ <div class="layui-input-inline">
39
+ <%= select_tag "area", options_for_select(EducodeSales::Common.where(clazz: 'area').pluck(:name, :id)), { include_blank: true } %>
40
+ </div>
41
+ </div>
42
+ <div class="layui-inline show_item_contract">
43
+ <label class="layui-form-label">中标时间</label>
44
+ <div class="layui-input-inline">
45
+ <input type="text" class="layui-input" id="bidded_date" name="bidded_date" placeholder=" - " autocomplete="off">
46
+ </div>
47
+ </div>
48
+ <div class="layui-inline show_item_contract">
49
+ <label class="layui-form-label">签单时间</label>
50
+ <div class="layui-input-inline">
51
+ <input type="text" class="layui-input" id="signed_date" name="signed_date" placeholder=" - " autocomplete="off">
52
+ </div>
53
+ </div>
54
+ <div class="layui-inline">
55
+ <button type="reset" class="layui-btn layui-btn-primary" lay-submit lay-filter="reset_business_search">重置
56
+ </button>
57
+ <button type="submit" id="search_bt" class="layui-btn layui-btn-primary" lay-submit lay-filter="search_bussiness_contract">搜索
58
+ </button>
59
+ </div>
60
+ </div>
61
+ </form>
62
+ </div>
63
+ <div id="sales_details_table_wraper">
64
+ <table class="layui-hide" id="sales_details_table" lay-filter="sales_details_table"></table>
65
+ </div>
66
+ </div>
67
+
68
+ <script type="text/html" id="currentTableBar">
69
+ <% if can? :add_follow, EducodeSales::Business %>
70
+ <a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="add">添加跟进</a>
71
+ <% end %>
72
+ <% if can? :edit_sales_detail, EducodeSales::Business %>
73
+ <a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="edit">编辑</a>
74
+ <% end %>
75
+ <% if can? :delete_sales_detail, EducodeSales::Business %>
76
+ <a class="layui-btn layui-btn-danger layui-btn-xs data-count-delete" lay-event="delete">删除</a>
77
+ <% end %>
78
+ <% if can?(:create, EducodeSales::SalePlan) %>
79
+ <a class="layui-btn layui-btn-default layui-btn-xs data-count-edit" lay-event="add_month_plan">添加月计划</a>
80
+ <% end %>
81
+ <% if can?(:show_file, EducodeSales::Business) %>
82
+ <a class="layui-btn layui-btn-default layui-btn-xs data-count-edit" lay-event="file">附件</a>
83
+ <% end %>
84
+
85
+ </script>
86
+
87
+ <script type="text/html" id="toolbar_contract">
88
+ <div class="layui-btn-container">
89
+ <span class="table-label">销售明细</span>
90
+ </div>
91
+ </script>
92
+ <script>
93
+ layui.use(['form', 'table', 'miniPage', 'element', 'request', 'laydate', 'dropdown', 'laytpl', 'xmSelect'], function() {
94
+ var $ = layui.jquery,
95
+ form = layui.form,
96
+ request = layui.request,
97
+ miniPage = layui.miniPage,
98
+ dropdown = layui.dropdown,
99
+ xmSelect = layui.xmSelect,
100
+ laydate = layui.laydate;
101
+ var openWH = miniPage.getOpenWidthHeight();
102
+ laydate.render({
103
+ elem: '#date',
104
+ range: true
105
+ });
106
+
107
+
108
+ laydate.render({
109
+ elem: '#bidded_date',
110
+ range: true,
111
+ value: gon.bidded_date
112
+ });
113
+ laydate.render({
114
+ elem: '#signed_date',
115
+ range: true,
116
+ value: gon.signed_date
117
+ });
118
+
119
+
120
+ var business_step_list = xmSelect.render({
121
+ el: '#contract_business_step',
122
+ data: gon.business_step
123
+ })
124
+
125
+ var data = form.val("search_form");
126
+ table = layui.table;
127
+ var cols_table = [
128
+ [{
129
+ field: 'id',
130
+ width: 60,
131
+ title: '序号',
132
+ type: 'numbers',
133
+ fixed: "left"
134
+ }, {
135
+ field: 'number',
136
+ width: 120,
137
+ title: '合同编号',
138
+ fixed: 'left',
139
+ }, {
140
+ field: 'name',
141
+ width: 120,
142
+ title: '商机名称',
143
+ }, {
144
+ field: 'school',
145
+ width: 180,
146
+ title: '用户单位',
147
+ }, {
148
+ field: 'department',
149
+ width: 180,
150
+ title: '部门',
151
+ }, {
152
+ field: 'majors',
153
+ width: 150,
154
+ title: '专业',
155
+ }, {
156
+ field: 'signed_department',
157
+ title: '签约单位',
158
+ width: 280,
159
+ }, {
160
+ field: 'actual_amount',
161
+ width: 120,
162
+ title: '合同金额',
163
+ }, {
164
+ field: 'item_clazz',
165
+ width: 100,
166
+ title: '销售品目',
167
+ }, {
168
+ field: 'brand',
169
+ width: 150,
170
+ title: '品牌',
171
+ }, {
172
+ field: 'specification',
173
+ width: 150,
174
+ title: '规格型号',
175
+ }, {
176
+ field: 'unit',
177
+ width: 90,
178
+ title: '单位',
179
+ }, {
180
+ field: 'amount',
181
+ width: 100,
182
+ title: '数量',
183
+ }, {
184
+ field: 'total_price',
185
+ width: 100,
186
+ title: '金额',
187
+ }, {
188
+ field: 'source_method',
189
+ width: 100,
190
+ title: '来源方式',
191
+ }, {
192
+ field: 'custom_clazz',
193
+ width: 100,
194
+ title: '定制类型',
195
+ }, {
196
+ field: 'supplier',
197
+ width: 120,
198
+ title: '供货商',
199
+ sort: true,
200
+ }, {
201
+ field: 'delivery_date',
202
+ width: 120,
203
+ title: '交货时间',
204
+ sort: true,
205
+ }, {
206
+ title: '操作',
207
+ minWidth: 350,
208
+ toolbar: '#currentTableBar',
209
+ align: "center",
210
+ fixed: 'right'
211
+ }]
212
+ ]
213
+
214
+
215
+ var sales_details_table = table.render({
216
+ elem: '#sales_details_table',
217
+ url: '/missions/sales_details',
218
+ autoSort: false,
219
+ where: {
220
+ q: data
221
+ },
222
+ defaultToolbar: ['filter'],
223
+ title: '销售明细数据表',
224
+ totalRow: true, //开启合并行
225
+ cols: cols_table,
226
+ toolbar: '#toolbar_contract',
227
+ limit: 20,
228
+ limits: [10, 15, 20, 30, 40, 50, 60, 70, 80, 90],
229
+ page: true,
230
+ skin: 'line',
231
+ });
232
+
233
+
234
+ var sort = {},
235
+ search = data;
236
+
237
+ table.on('sort(sales_details_table)', function(obj) {
238
+ var data = form.val("search_form");
239
+ sort.field = obj.field;
240
+ sort.order = obj.type;
241
+ table.reload('sales_details_table', {
242
+ url: '/missions/sales_details',
243
+ initSort: obj,
244
+ where: {
245
+ sort: sort,
246
+ q: search
247
+ }
248
+ });
249
+ })
250
+
251
+ // 监听搜索操作
252
+ form.on('submit(search_bussiness_contract)', function(data) {
253
+ if (search['clazz']) {
254
+ data.field['clazz'] = search['clazz']
255
+ }
256
+ var business_step = [];
257
+ business_step_list.getValue().forEach(function(d) {
258
+ business_step.push(d.value);
259
+ })
260
+ data.field.business_step = business_step.toString();
261
+ search = data.field
262
+ table.reload('sales_details_table', {
263
+ url: '/missions/sales_details',
264
+ page: {
265
+ curr: 1
266
+ },
267
+ where: {
268
+ q: search,
269
+ sort: sort
270
+ }
271
+ }, 'data');
272
+
273
+ return false;
274
+ });
275
+
276
+ form.on('submit(reset_business_search)', function(data) {
277
+ var field = data.field;
278
+ form.val('search_form', {
279
+ name: '',
280
+ area: '',
281
+ department: '',
282
+ business_type: '',
283
+ business_step: '',
284
+ place_id: '',
285
+ bidded_date: '',
286
+ signed_department: '',
287
+ signed_date: '',
288
+ sales_staff_id: '',
289
+ })
290
+ business_step_list.setValue([])
291
+ .setValue([])
292
+ return false;
293
+ });
294
+
295
+ table.on('tool(sales_details_table)', function(obj) {
296
+ var data = obj.data;
297
+ id = data.id
298
+ if (obj.event === 'add') { // 监听添加操作
299
+ business_id = data.business_id
300
+ var content = miniPage.getHrefContent('/missions/businesses/new_follow_record?id=' + data.business_id);
301
+ var openWH = miniPage.getOpenWidthHeight();
302
+ sale_plan_index = layer.open({
303
+ title: '添加商机跟进记录',
304
+ type: 1,
305
+ shade: 0.2,
306
+ maxmin: true,
307
+ shadeClose: true,
308
+ area: [openWH[0] + 'px', openWH[1] + 'px'],
309
+ offset: [openWH[2] + 'px', openWH[3] + 'px'],
310
+ content: content,
311
+ success: function (layero, index) {
312
+ form.render('select');
313
+ }
314
+ });
315
+ $(window).on("resize", function () {
316
+ layer.full(sale_plan_index);
317
+ });
318
+ } else if (obj.event === 'edit') {
319
+ var content = miniPage.getHrefContent('/missions/sales_details/' + id + '/edit');
320
+ var openWH = miniPage.getOpenWidthHeight();
321
+ name = data.name;
322
+ sindex = layer.open({
323
+ title: '编辑',
324
+ type: 1,
325
+ shade: 0.2,
326
+ maxmin: true,
327
+ shadeClose: true,
328
+ area: [openWH[0] + 'px', openWH[1] + 'px'],
329
+ offset: [openWH[2] + 'px', openWH[3] + 'px'],
330
+ content: content,
331
+ success: function (layero, index) {
332
+ form.render('select');
333
+ }
334
+ });
335
+ $(window).on("resize", function() {
336
+ layer.full(sindex);
337
+ });
338
+ return false;
339
+ } else if (obj.event === 'add_month_plan') {
340
+ id = obj.data.business_id;
341
+ var content = miniPage.getHrefContent('/missions/plans/new_month?business_id=' + obj.data.business_id);
342
+ var openWH = miniPage.getOpenWidthHeight();
343
+ sindex = layer.open({
344
+ title: '添加月计划',
345
+ type: 1,
346
+ shade: 0.2,
347
+ maxmin: true,
348
+ shadeClose: true,
349
+ area: [openWH[0] + 'px', openWH[1] + 'px'],
350
+ offset: [openWH[2] + 'px', openWH[3] + 'px'],
351
+ content: content
352
+ });
353
+ $(window).on("resize", function () {
354
+ layer.full(sindex);
355
+ });
356
+ } else if (obj.event == 'file') {
357
+ name = obj.data.name;
358
+ id = obj.data.business_id;
359
+ var content = miniPage.getHrefContent('/missions/businesses/file?business_id=' + obj.data.business_id);
360
+ var openWH = miniPage.getOpenWidthHeight();
361
+ sindex = layer.open({
362
+ title: '商机列表/'+name+'的附件信息',
363
+ type: 1,
364
+ shade: 0.2,
365
+ // maxmin: true,
366
+ shadeClose: true,
367
+ area: [openWH[0] + 'px', openWH[1] + 'px'],
368
+ offset: [openWH[2] + 'px', openWH[3] + 'px'],
369
+ content: content
370
+ });
371
+ $(window).on("resize", function () {
372
+ // layer.full(sindex);
373
+ });
374
+ } else if (obj.event == 'delete') {
375
+ name = obj.data.name;
376
+ layer.confirm('确定删除' + data.name, function (index) {
377
+ request.delete('missions/sales_details/' + data.id, {}, function (res) {
378
+ layer.close(index);
379
+ table.reload("sales_details_table")
380
+ })
381
+ });
382
+ }
383
+ });
384
+
385
+
386
+ });
387
+ </script>
388
+ <style>
389
+ .layui-table-tool-temp {
390
+ padding-right: 30px;
391
+ !important;
392
+ }
393
+
394
+ .layui-table-fixed .layui-table-body {
395
+ height: auto!important;
396
+ }
397
+
398
+ .layui-table-fixed.layui-hide {
399
+ display: block!important;
400
+ }
401
+ </style>
@@ -0,0 +1,34 @@
1
+ json.data do
2
+ json.array! @sales_details do |d|
3
+ json.id d.id
4
+ json.business_id d.business_id
5
+ json.number d.business.number
6
+ json.name d.business.name
7
+ json.department d.business.department&.name
8
+ json.school d.business.department&.school&.name
9
+ json.school_id d.business.department&.school_id
10
+
11
+ json.actual_amount d.business.last_follow_up&.actual_amount.to_f.round(2)
12
+ json.created_at d.created_at.to_s
13
+ json.staff_manages d.business.last_follow_up&.assign_follow_ups.present? ? (d.business.last_follow_up.assign_follow_ups.map{ |d| d.staff.user.real_name}.join("、")) : d.business.staff&.user&.real_name
14
+ json.area d.business.department&.school&.province
15
+
16
+ json.majors d.business.department&.department_majors&.pluck(:name).present? ? d.business.department&.department_majors&.pluck(:name).join(",") : ""
17
+ json.signed_department d.business.last_follow_up&.signed_department&.school&.name || ''
18
+ json.item_clazz d.product_catalog.item_clazz
19
+ json.brand d.product_catalog.brand
20
+ json.specification d.product_catalog.specification
21
+ json.unit d.product_catalog.unit
22
+ json.amount d.amount
23
+ json.total_price d.total_price
24
+ json.source_method d.product_catalog.source_method
25
+ json.custom_clazz d.custom_clazz
26
+ json.supplier d.product_catalog.supplier
27
+ json.delivery_date d.delivery_date
28
+ end
29
+ end
30
+
31
+
32
+ json.code 0
33
+ json.count @sales_details.total_count
34
+ json.msg 'succcess'
@@ -71,8 +71,10 @@
71
71
  <dd><a href="/missions/contracts/product_list" class="<%= current?('layui-this', product_list_contracts_path) %>"><i style="padding-right: 35px"></i><%= image_tag "educode_sales/4.商机管理.png",size:"15"%><i style="font-size: 25px; padding-right: 15px"></i>产品目录</a>
72
72
  </dd>
73
73
  <% end %>
74
+ <% if can? :read_sales_detail, EducodeSales::Business %>
74
75
  <dd><a href="/missions/sales_details" class="<%= current?('layui-this', sales_details_path) %>"><i style="padding-right: 35px"></i><%= image_tag "educode_sales/4.商机管理.png",size:"15"%><i style="font-size: 25px; padding-right: 15px"></i>销售明细</a>
75
76
  </dd>
77
+ <% end %>
76
78
  <% if can? :read, EducodeSales::MoneyPlan %>
77
79
  <dd><a href="/missions/money_plans" class="<%= current?('layui-this', money_plans_path) %>"><i style="padding-right: 35px"></i><%= image_tag "educode_sales/money_plans.png",size:"15"%><i style="font-size: 25px; padding-right: 15px"></i>回款计划</a>
78
80
  </dd>
data/config/routes.rb CHANGED
@@ -35,6 +35,9 @@ EducodeSales::Engine.routes.draw do
35
35
  get :new_product
36
36
  post :product_catalog
37
37
  get :show_follow_record
38
+ get :new_sales_detail
39
+ get :select_product
40
+ post :sales_detail
38
41
  end
39
42
  member do
40
43
  post :advise
@@ -12,5 +12,9 @@ class CreateEducodeSalesSalesDetails < ActiveRecord::Migration[5.2]
12
12
 
13
13
  t.timestamps
14
14
  end
15
+
16
+ EducodeSales::Permission.find_or_create_by(name: '查看销售明细', subject: 'Business', action: 'read_sales_detail', clazz: 'contract')
17
+ EducodeSales::Permission.find_or_create_by(name: '编辑销售明细', subject: 'Business', action: 'edit_sales_detail', clazz: 'contract')
18
+ EducodeSales::Permission.find_or_create_by(name: '删除销售明细', subject: 'Business', action: 'delete_sales_detail', clazz: 'contract')
15
19
  end
16
20
  end
@@ -1,3 +1,3 @@
1
1
  module EducodeSales
2
- VERSION = '0.9.84'
2
+ VERSION = '0.9.86'
3
3
  end
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: educode_sales
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.84
4
+ version: 0.9.86
5
5
  platform: ruby
6
6
  authors:
7
7
  - anke1460
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2023-05-11 00:00:00.000000000 Z
@@ -105,7 +105,6 @@ files:
105
105
  - app/assets/images/educode_sales/icon-login.png
106
106
  - app/assets/images/educode_sales/icon.png
107
107
  - app/assets/images/educode_sales/indexLogo.png
108
- - app/assets/images/educode_sales/indexlogo.png
109
108
  - app/assets/images/educode_sales/loading-0.gif
110
109
  - app/assets/images/educode_sales/loading-1.gif
111
110
  - app/assets/images/educode_sales/loading-2.gif
@@ -321,8 +320,10 @@ files:
321
320
  - app/views/educode_sales/contracts/list.js.erb
322
321
  - app/views/educode_sales/contracts/new_follow_up.html.erb
323
322
  - app/views/educode_sales/contracts/new_product.html.erb
323
+ - app/views/educode_sales/contracts/new_sales_detail.html.erb
324
324
  - app/views/educode_sales/contracts/product_list.html.erb
325
325
  - app/views/educode_sales/contracts/product_list.json.jbuilder
326
+ - app/views/educode_sales/contracts/select_product.html.erb
326
327
  - app/views/educode_sales/contracts/show_follow_record.html.erb
327
328
  - app/views/educode_sales/customers/edit.html.erb
328
329
  - app/views/educode_sales/customers/edit_department.html.erb
@@ -538,7 +539,9 @@ files:
538
539
  - app/views/educode_sales/sales/school.html.erb
539
540
  - app/views/educode_sales/sales/trends.html.erb
540
541
  - app/views/educode_sales/sales/xschool.html.erb
542
+ - app/views/educode_sales/sales_details/edit.html.erb
541
543
  - app/views/educode_sales/sales_details/index.html.erb
544
+ - app/views/educode_sales/sales_details/index.json.jbuilder
542
545
  - app/views/educode_sales/sessions/login.html.erb
543
546
  - app/views/educode_sales/staffs/edit.html.erb
544
547
  - app/views/educode_sales/staffs/follow_up_departments.json.jbuilder
@@ -679,7 +682,7 @@ homepage: https://www.educoder.net
679
682
  licenses:
680
683
  - MIT
681
684
  metadata: {}
682
- post_install_message:
685
+ post_install_message:
683
686
  rdoc_options: []
684
687
  require_paths:
685
688
  - lib
@@ -695,7 +698,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
695
698
  version: '0'
696
699
  requirements: []
697
700
  rubygems_version: 3.0.9
698
- signing_key:
701
+ signing_key:
699
702
  specification_version: 4
700
703
  summary: Summary of EducodeSales.
701
704
  test_files: []