Compare commits
103 Commits
feature/we
...
feature/销售
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77c303e1fe | ||
|
|
ba9ce1f0ee | ||
|
|
41cd76ad14 | ||
|
|
e20510bc4f | ||
|
|
1d14ab27af | ||
|
|
fd55abec72 | ||
|
|
76597f6ccb | ||
|
|
d7779e969d | ||
|
|
27339afaae | ||
|
|
4fd7ad8d03 | ||
|
|
3bc33fe2fc | ||
|
|
c21319a127 | ||
|
|
02e21a8fde | ||
|
|
2cf578de65 | ||
|
|
9665cdfc84 | ||
|
|
bef7376827 | ||
|
|
e73e9d6960 | ||
|
|
892f5d0e70 | ||
|
|
61339da204 | ||
|
|
25db392864 | ||
|
|
745fd429c2 | ||
|
|
5c59a27a81 | ||
|
|
9bac3675f6 | ||
|
|
b4fbbd48fb | ||
|
|
3559d67c05 | ||
|
|
816623b1fe | ||
|
|
91b913a7bd | ||
|
|
ba8393a8c7 | ||
|
|
06d061165b | ||
|
|
18a7dbbff9 | ||
|
|
dc545e6d49 | ||
|
|
1467dbf88c | ||
|
|
e9caf78b81 | ||
|
|
aa1353cf99 | ||
|
|
14d49f2944 | ||
|
|
8560069b19 | ||
|
|
8dc23a638f | ||
|
|
5363557faf | ||
|
|
3c026004f3 | ||
|
|
651c8f266b | ||
|
|
a3bfbe66c4 | ||
|
|
563e40adc6 | ||
|
|
f88a784a87 | ||
|
|
01df5e86cd | ||
|
|
41f853b6c9 | ||
|
|
906a0ea767 | ||
|
|
6162c731f2 | ||
|
|
4f1d518ef3 | ||
|
|
06eaebd098 | ||
|
|
8578a9a538 | ||
|
|
b9039ef466 | ||
|
|
a97f581c99 | ||
|
|
036179ec4d | ||
|
|
d33188dedf | ||
|
|
7033f95273 | ||
|
|
00689d76cc | ||
|
|
86d97ef331 | ||
|
|
05a183f46f | ||
|
|
50959d2e9c | ||
|
|
519ce0d5bb | ||
|
|
f06842cdcb | ||
|
|
d5a1caad10 | ||
|
|
e51fff4120 | ||
|
|
2fe8e0e356 | ||
|
|
bbe2e5792f | ||
|
|
a1a520ec39 | ||
|
|
1b714a9962 | ||
|
|
9d133096c7 | ||
|
|
69f3453134 | ||
|
|
ab10271b4d | ||
|
|
516a98e102 | ||
|
|
390213881a | ||
|
|
ac2eba4734 | ||
|
|
b64893436b | ||
|
|
ee148239d2 | ||
|
|
4cc03aee9b | ||
|
|
31a703952c | ||
|
|
ae08c5b56e | ||
|
|
dc76dcdc2f | ||
|
|
6a040d16ea | ||
|
|
30e8d04b70 | ||
|
|
2b3375ad41 | ||
|
|
8a059a5520 | ||
|
|
49a2f02b54 | ||
|
|
ef92f24d35 | ||
|
|
0207914592 | ||
|
|
5776c97744 | ||
|
|
180cdf2a08 | ||
|
|
47720948ff | ||
|
|
7814a2b622 | ||
|
|
06981fb894 | ||
|
|
19dbd9901d | ||
|
|
4985b0a85d | ||
|
|
39f99d6ce7 | ||
|
|
c8f25ea4b3 | ||
|
|
cab9e08066 | ||
|
|
2b83f82989 | ||
|
|
598e8fee9c | ||
|
|
6f3a788101 | ||
|
|
30ff349b37 | ||
|
|
4018797384 | ||
|
|
a1efde6ef9 | ||
|
|
3f84972bfd |
@@ -1,2 +1,5 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_jikimo_workorder_exception","access.jikimo.workorder.exception","model_jikimo_workorder_exception","mrp.group_mrp_user",1,1,1,0
|
||||
"access_jikimo_workorder_exception_group_quality","access.jikimo.workorder.exception.group_quality","model_jikimo_workorder_exception","sf_base.group_quality",1,1,1,0
|
||||
"access_jikimo_workorder_exception_group_quality_director","access.jikimo.workorder.exception.group_quality_director","model_jikimo_workorder_exception","sf_base.group_quality_director",1,1,1,0
|
||||
|
||||
|
||||
|
@@ -21,4 +21,12 @@ class ProductCategory(models.Model):
|
||||
args += [('name', 'not in', ['Saleable', 'Expenses', 'Deliveries'])]
|
||||
|
||||
# 调用父类的 name_search 方法
|
||||
return super(ProductCategory, self).name_search(name, args=args, operator=operator, limit=limit)
|
||||
return super(ProductCategory, self).name_search(name, args=args, operator=operator, limit=limit)
|
||||
|
||||
@api.model
|
||||
def search(self, args, limit=100, offset=0, order=None, count=False):
|
||||
# 添加过滤条件,确保只返回名称不在指定列表中的记录
|
||||
args += [('name', 'not in', ['Saleable', 'Expenses', 'Deliveries'])]
|
||||
|
||||
# 调用父类的 search 方法
|
||||
return super(ProductCategory, self).search(args, limit=limit, offset=offset, order=order, count=count)
|
||||
125
sf_base/static/js/customTable.js
Normal file
125
sf_base/static/js/customTable.js
Normal file
@@ -0,0 +1,125 @@
|
||||
// 获取表格数据
|
||||
function getDomData() {
|
||||
const dom = $('div[name=cutting_speed_ids]')
|
||||
if (!dom.length) return
|
||||
const table = dom.find('.o_list_table')
|
||||
const thead = table.children('thead')
|
||||
const tbody = table.children('tbody')
|
||||
const tbody_child = tbody.children()
|
||||
const hideTheadDom = thead.find('[data-name=process_capability]')
|
||||
hideTheadDom.hide().next().hide()
|
||||
hideTheadDom.before('<th customTh>精加工</th><th customTh>粗加工</th>')
|
||||
tbody_child.each(function () {
|
||||
const dom = $(this).children('[name=process_capability]')
|
||||
if(!dom.length) return
|
||||
dom.css('cssText', 'display: none!important').next().css('cssText', 'display: none!important')
|
||||
const isCu = dom.text() == '粗加工' // 是否粗加工
|
||||
const v = dom.next().text() // 切削速度
|
||||
dom.after(`<td customSpeed="1" name="process_capability" is="精加工" val="${ v }">${!isCu ? v : ''}</td><td customSpeed="1" name="process_capability" is="粗加工" val="${ v }">${isCu ? v : ''}</td>`)
|
||||
setListenClick()
|
||||
})
|
||||
return;
|
||||
handleTbody(tbody, newTableData, ΦList, table)
|
||||
}
|
||||
|
||||
// 监听点击
|
||||
function setListenClick() {
|
||||
$(document).click(function (e) {
|
||||
if ($(e.target).attr('customSpeed')) {
|
||||
const orginV = $('[customInput=1]').children('input').val()
|
||||
$('[customInput=1]').parent().html(orginV)
|
||||
const v = $(e.target).attr('val')
|
||||
const is = $(e.target).attr('is')
|
||||
$(e.target).html('')
|
||||
const input = $('<div customInput="1" is="' + is + '" class="o_field_widget o_field_char"><input class="o_input" type="text" autocomplete="off" maxlength="20"></div>')
|
||||
input.children('input').val(v)
|
||||
$(e.target).append(input)
|
||||
input.children('input').focus()
|
||||
input.children('input').select()
|
||||
} else if ($(e.target).attr('customInput')) {
|
||||
|
||||
} else {
|
||||
const orginV = $('[customInput=1]').children('input').val()
|
||||
$('[customInput=1]').parent().html(orginV)
|
||||
const v = $(e.target).attr('val')
|
||||
}
|
||||
})
|
||||
$(document).off('change') // 防止重复绑定
|
||||
$(document).on('change', '[customInput] input', async function () {
|
||||
$(this).parents('td').attr('val', $(this).val())
|
||||
$(this).parents('td').siblings('[customspeed]').attr('val', $(this).val())
|
||||
var eve1 = new Event('change')
|
||||
var eve2 = new Event('input')
|
||||
var eve3 = new Event('click')
|
||||
let patchSpeedDom = $(this).parents('td').siblings('[name=cutting_speed]')
|
||||
let patchProcessDom = $(this).parents('td').siblings('[name=process_capability]')
|
||||
$(this).parents('td').siblings('[customspeed]').text('') // 清空其他加工类型的数据
|
||||
await timeOut(500)
|
||||
patchProcessDom[0].dispatchEvent(eve3)
|
||||
await timeOut(200)
|
||||
const processVal = $(this).parent().attr('is')
|
||||
patchProcessDom.find('select').val(`"${processVal}"`) // 设置源select的val为“加工类型 is”、
|
||||
patchProcessDom.attr("data-tooltip", `${processVal}`)
|
||||
patchProcessDom.find('select')[0].dispatchEvent(eve1)
|
||||
|
||||
patchSpeedDom[0].dispatchEvent(eve3)
|
||||
await timeOut(200)
|
||||
patchSpeedDom.find('input').val($(this).val())
|
||||
await timeOut(50)
|
||||
patchSpeedDom.find('input')[0].dispatchEvent(eve2)
|
||||
patchSpeedDom.find('input')[0].dispatchEvent(eve1)
|
||||
})
|
||||
$(document).off('blur') // 防止重复绑定
|
||||
$(document).on('blur', '[customInput] input', async function () {
|
||||
if(!$(this).length) return
|
||||
|
||||
$(this).parents('td').siblings('[customspeed]').text('') // 清空其他加工类型的数据
|
||||
let patchProcessDom = $(this).parents('td').siblings('[name=process_capability]')
|
||||
try {
|
||||
patchProcessDom[0].dispatchEvent(new Event('click'))
|
||||
const processVal = $(this).parent().attr('is')
|
||||
patchProcessDom.find('select').val(`"${processVal}"`) // 设置源select的val为“加工类型 is”、
|
||||
patchProcessDom.attr("data-tooltip", `${processVal}`)
|
||||
patchProcessDom.find('select')[0].dispatchEvent(new Event('change'))
|
||||
} catch {
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
function timeOut(time) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, time)
|
||||
})
|
||||
}
|
||||
|
||||
function listenAdd() {
|
||||
$('td.o_field_x2many_list_row_add a').click(async function () {
|
||||
await timeOut(500)
|
||||
const tr = $('.o_list_table').children('tbody').children('tr').eq(-2)
|
||||
if(tr.children('td').eq(2).text() == '') {
|
||||
const dom = tr.children('[name=process_capability]')
|
||||
if(!dom.length) return
|
||||
dom.css('cssText', 'display: none!important').next().css('cssText', 'display: none!important')
|
||||
const isCu = dom.text() == '粗加工' // 是否粗加工
|
||||
const v = dom.next().text() // 切削速度
|
||||
dom.after(`<td customSpeed="1" name="process_capability" is="精加工" val="${ v }">${!isCu ? v : ''}</td><td customSpeed="1" name="process_capability" is="粗加工" val="${ v }">${isCu ? v : ''}</td>`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function listenSave() {
|
||||
$('.o_form_button_save').click( async function () {
|
||||
await timeOut(1000)
|
||||
if($(this).parent().next().length) return
|
||||
$('th[customTh],td[cusomSpeed]').remove()
|
||||
getDomData()
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
listenAdd()
|
||||
listenSave()
|
||||
getDomData()
|
||||
47
sf_base/static/js/setTableWidth.js
Normal file
47
sf_base/static/js/setTableWidth.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// 因为表格可以拖动设置宽度,所以需要用js设置初始宽度
|
||||
function setBasicParamTableWidth() {
|
||||
// const _100px = 'th[data-name="cutting_blade_length"],th[data-name="cutting_blade_length"],th[data-name="name"],th[data-name="tip_handling_size"],th[data-name="cutting_depth_max"],th[data-name="diameter_inner_circle"],th[data-name="diameter_mounting_hole" ],th[data-name="radius_tip_re" ],th[data-name="is_chip_breaker"],th[data-name="chip_breaker_type_code"],th[data-name="blade_profile"]'
|
||||
// const _65px = 'th[data-name="edge_angle"],th[data-name="relief_angle"],[data-name="total_length"],th[data-name="length"],th[data-name="thickness"],th[data-name="blade_number"]'
|
||||
// const _80px = 'th[data-name="arbor_diameter"],th[data-name="head_height"],th[data-name="head_width"],th[data-name="head_length"],th[data-name="blade_diameter"],th[data-name="blade_length"] ,th[data-name="neck_length"] ,th[data-name="neck_diameter"] ,th[data-name="shank_diameter"],th[data-name="shank_length"],th[data-name="tip_diameter"],th[data-name="knife_tip_taper"],th[data-name="blade_helix_angle"] ,th[data-name="blade_width"],th[data-name="blade_depth"]'
|
||||
// const _50px = 'th[data-name="pitch"],th[data-name="width"],th[data-name="height"]'
|
||||
|
||||
const basicParamDom = $('.fixTableCss')
|
||||
// const basicParamDom_100px = basicParamDom.find(_100px) // 四字以上
|
||||
// const basicParamDom_65px = basicParamDom.find(_65px) // 大概三个字加单位
|
||||
// const basicParamDom_80px = basicParamDom.find(_80px) // 大概四个字加单位
|
||||
// const basicParamDom_50px= basicParamDom.find(_50px) // 大概两个字加单位
|
||||
//
|
||||
// basicParamDom_100px.css({'width': '100px', 'max-width': 'auto', ',min-width': 'auto'})
|
||||
// basicParamDom_65px.css({'width': '65px', 'max-width': 'auto', ',min-width': 'auto'})
|
||||
// basicParamDom_80px.css({'width': '80px', 'max-width': 'auto', ',min-width': 'auto'})
|
||||
// basicParamDom_50px.css({'width': '50px', 'max-width': 'auto', ',min-width': 'auto'})
|
||||
let dom = []
|
||||
try {
|
||||
dom = basicParamDom.find('table').find('thead').children().children()
|
||||
|
||||
} catch {
|
||||
dom = []
|
||||
}
|
||||
if (!dom) return
|
||||
dom.each(function () {
|
||||
if ($(this).hasClass('row_no') >= 0) { // 序号列
|
||||
// 不设置 通过css设置
|
||||
}
|
||||
const text = $(this).text().split('(')
|
||||
if ($(this).attr('data-name') == 'name' || text[0].length > 4) {
|
||||
$(this).width('100px')
|
||||
} else if(text[0].length == 4){
|
||||
$(this).width('80px')
|
||||
} else if(text[0].length == 3){
|
||||
$(this).width('65px')
|
||||
} else if(text[0].length == 2){
|
||||
$(this).width('50px')
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
setBasicParamTableWidth()
|
||||
$('.o_field_many2one_selection').on('click', $('#cutting_tool_material_id + ul'), function () {
|
||||
setTimeout(setBasicParamTableWidth, 500)
|
||||
})
|
||||
159
sf_base/static/js/updateTable.js
Normal file
159
sf_base/static/js/updateTable.js
Normal file
@@ -0,0 +1,159 @@
|
||||
// 获取表格数据
|
||||
function getDomData() {
|
||||
const dom = $('#updateTable').prev()
|
||||
if (!dom.length) return
|
||||
const table = $('#updateTable').prev().find('.o_list_table')
|
||||
const customTable = table.clone()
|
||||
customTable.addClass('customTable')
|
||||
table.parent().append(customTable)
|
||||
table.hide()
|
||||
const thead = customTable.children('thead')
|
||||
const tbody = customTable.children('tbody')
|
||||
const tableData = []
|
||||
const tbody_child = tbody.children()
|
||||
|
||||
const tbody_child_len = tbody_child.length
|
||||
|
||||
for (let v = 0; v < tbody_child_len; v++) { // 将数据取出来到tableData里面
|
||||
const data = tbody_child[v].innerText.split('\t')
|
||||
// console.log('dom data',data)
|
||||
const [index, deep, name, Φ, value] = data
|
||||
tableData.push({index, deep, name, Φ, value})
|
||||
}
|
||||
const ΦList = [...new Set(tableData.map(_ => _.name))] // ΦList去重
|
||||
const newTableData = {}
|
||||
tableData.forEach(_ => {
|
||||
const key = _.deep + '|' + _.Φ
|
||||
!newTableData[key] ? newTableData[key] = {i: _.index} : '';
|
||||
if (_.Φ) { // 去除没有Φ的脏数据
|
||||
newTableData[key]['Φ' + _.Φ] = _.value
|
||||
newTableData[key]['Φ' + _.Φ + 'i'] = _.index
|
||||
}
|
||||
})
|
||||
// console.log('qwdh',tableData, ΦList, newTableData);
|
||||
|
||||
if (ΦList.filter(_ => _).length == 0) return;
|
||||
handleThead(thead, ΦList)
|
||||
|
||||
handleTbody(tbody, newTableData, ΦList, table)
|
||||
}
|
||||
|
||||
// 重新设置表头、
|
||||
function handleThead(thead, ΦList) {
|
||||
const dom = thead.children().eq(0).children()
|
||||
const len = dom.length
|
||||
dom.eq(0).attr('rowspan', 2)
|
||||
dom.eq(1).attr('rowspan', 2)
|
||||
len == 5 ? dom.eq(2).attr('rowspan', 2) : ''
|
||||
dom.eq(-2).attr('colspan', ΦList.length)
|
||||
dom.eq(-1).remove()
|
||||
|
||||
const tr = document.createElement('tr')
|
||||
for (let v = 0; v < ΦList.length; v++) {
|
||||
const th = document.createElement('th')
|
||||
th.innerText = 'Φ' + ΦList[v]
|
||||
tr.append(th)
|
||||
}
|
||||
thead.append(tr)
|
||||
}
|
||||
|
||||
// 重新设置表格
|
||||
function handleTbody(tbody, newTableData, ΦList, table) {
|
||||
console.log(newTableData)
|
||||
tbody.html('')
|
||||
let i = 0
|
||||
const data = Object.keys(newTableData)
|
||||
// data.sort((a, b) => {
|
||||
// a = a.split('=')[1].split('%')[0]
|
||||
// b = b.split('=')[1].split('%')[0]
|
||||
// return a - b
|
||||
// })
|
||||
// console.log('wqoqw ',ΦList)
|
||||
data.forEach(_ => {
|
||||
i++
|
||||
const tr = $('<tr class="o_data_row"></tr>')
|
||||
const td0 = $('<td></td>')
|
||||
td0.text(i)
|
||||
tr.append(td0)
|
||||
const lit = _.split('|')
|
||||
//
|
||||
const td1 = $('<td></td>')
|
||||
const td2 = $('<td></td>')
|
||||
td1.text(lit[0])
|
||||
td2.text(lit[1] || '')
|
||||
tr.append(td1)
|
||||
tr.append(td2)
|
||||
ΦList.forEach(Φ => {
|
||||
const td = $('<td class="o_data_cell cursor-pointer o_field_cell o_list_char"></td>')
|
||||
td.text(newTableData[_]['Φ' + Φ])
|
||||
td.attr('col', newTableData[_]['Φ' + Φ + 'i'])
|
||||
td.attr('val', newTableData[_]['Φ' + Φ])
|
||||
td.attr('coustomTd', 1)
|
||||
tr.append(td)
|
||||
})
|
||||
// // for (let j = 0; j < ΦList.length; j++) {
|
||||
// // const td = document.createElement('td')
|
||||
// // td.innerText = newTableData[data[v]][_]
|
||||
// // th.append(td)
|
||||
// // }
|
||||
tbody.append(tr)
|
||||
})
|
||||
// $(document).click(function (e) {
|
||||
// if ($(e.target).attr('coustomTd')) {
|
||||
// const orginV = $('[coustomInput=1]').children('input').val()
|
||||
// $('[coustomInput=1]').parent().html(orginV)
|
||||
// const v = $(e.target).attr('val')
|
||||
// console.log($(e.target));
|
||||
// $(e.target).html('')
|
||||
// const input = $('<div coustomInput="1" name="feed_per_tooth" class="o_field_widget o_field_char"><input class="o_input" type="text" autocomplete="off" maxlength="20"></div>')
|
||||
// input.children('input').val(v)
|
||||
// $(e.target).append(input)
|
||||
// input.children('input').focus()
|
||||
// input.children('input').select()
|
||||
// } else if ($(e.target).attr('coustomInput')) {
|
||||
//
|
||||
// } else {
|
||||
// const orginV = $('[coustomInput=1]').children('input').val()
|
||||
// $('[coustomInput=1]').parent().html(orginV)
|
||||
// const v = $(e.target).attr('val')
|
||||
// }
|
||||
// })
|
||||
// $(document).off('change') // 防止重复绑定
|
||||
// $(document).on('change', '[coustomInput] input', function () {
|
||||
// $(this).parents('td').attr('val', $(this).val());
|
||||
// var eve1 = new Event('change');
|
||||
// var eve2 = new Event('input');
|
||||
// var eve3 = new Event('click');
|
||||
// const i = $(this).parents('td').attr('col');
|
||||
// let patchDom = table.find('tbody').children('tr').eq(i - 1);
|
||||
//
|
||||
// if (patchDom.length === 0) {
|
||||
// console.error('No such row found');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// patchDom = patchDom.children().eq(-1);
|
||||
//
|
||||
// setTimeout(() => {
|
||||
// if (patchDom.length === 0) {
|
||||
// console.error('No such cell found');
|
||||
// return;
|
||||
// }
|
||||
// patchDom[0].dispatchEvent(eve3); // Simulate click event
|
||||
//
|
||||
// setTimeout(() => {
|
||||
// patchDom = patchDom.find('input');
|
||||
// if (patchDom.length === 0) {
|
||||
// console.error('No input found in the target cell');
|
||||
// return;
|
||||
// }
|
||||
// patchDom.val($(this).val());
|
||||
// patchDom[0].dispatchEvent(eve2);
|
||||
// patchDom[0].dispatchEvent(eve1);
|
||||
// }, 200);
|
||||
// }, 500);
|
||||
// });
|
||||
|
||||
}
|
||||
|
||||
getDomData()
|
||||
52
sf_base/static/src/scss/change.scss
Normal file
52
sf_base/static/src/scss/change.scss
Normal file
@@ -0,0 +1,52 @@
|
||||
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove) {
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
.text-truncate {
|
||||
overflow: unset !important;
|
||||
text-overflow: unset !important;
|
||||
white-space: unset !important;
|
||||
}
|
||||
|
||||
|
||||
// 设置表格不超出页面宽度
|
||||
.o_form_view .o_field_widget .o_list_renderer {
|
||||
width: calc(100% - 64px) !important;
|
||||
margin:0 auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
// 表格针对处理
|
||||
.fixTableCss {
|
||||
text-align: center;
|
||||
.o_list_number_th,.o_list_number {
|
||||
text-align: center!important;
|
||||
}
|
||||
.ui-sortable {
|
||||
tr > td:first-child {
|
||||
padding: 0!important;
|
||||
}
|
||||
}
|
||||
.row_no {
|
||||
padding: 0!important;;
|
||||
width: 35px!important;
|
||||
}
|
||||
|
||||
th[data-name="total_length"],th[data-name="length"],th[data-name="thickness"] {
|
||||
.flex-row-reverse {
|
||||
span {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 其他不能用js处理的表格
|
||||
.otherTableFix {
|
||||
th[data-name="cutting_tool_material_id"] {
|
||||
width: 100px!important;
|
||||
}
|
||||
th[data-name="ramping_angle_max"],th[data-name="ramping_angle_min"] {
|
||||
width: 200px!important;
|
||||
}
|
||||
}
|
||||
@@ -360,6 +360,7 @@
|
||||
<field name="cooling_jacket"/>
|
||||
</tree>
|
||||
</field>
|
||||
<script src="/sf_base/static/js/setTableWidth.js?time=3"></script>
|
||||
</page>
|
||||
<page string="切削速度Vc"
|
||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))]}">
|
||||
@@ -380,6 +381,9 @@
|
||||
<field name="cutting_speed"/>
|
||||
</tree>
|
||||
</field>
|
||||
<script src="/sf_base/static/js/customTable.js?time=3"></script>
|
||||
<script src="/sf_base/static/js/setTableWidth.js?time=3"></script>
|
||||
|
||||
</page>
|
||||
<page string="每齿走刀量fz"
|
||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))]}">
|
||||
@@ -392,6 +396,8 @@
|
||||
<field name="feed_per_tooth"/>
|
||||
</tree>
|
||||
</field>
|
||||
<div id="updateTable"></div>
|
||||
<script src="/sf_base/static/js/updateTable.js?time=3"></script>
|
||||
<field name="feed_per_tooth_ids_3"
|
||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('刀片'))]}">
|
||||
<tree editable="bottom" class="center" create="0" delete="0">
|
||||
|
||||
@@ -36,6 +36,7 @@ class StatusChange(models.Model):
|
||||
# 使用super()来调用原始方法(在本例中为'sale.order'模型的'action_confirm'方法)
|
||||
try:
|
||||
res = super(StatusChange, self).action_confirm()
|
||||
logging.info('原生方法返回结果:%s' % res)
|
||||
# 原有方法执行后,进行额外的操作(如调用外部API)
|
||||
process_start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
config = self.env['res.config.settings'].get_values()
|
||||
@@ -61,6 +62,7 @@ class StatusChange(models.Model):
|
||||
traceback_error = traceback.format_exc()
|
||||
logging.error("工厂加工同步订单状态失败:%s " % traceback_error)
|
||||
raise UserError(e)
|
||||
logging.info('最终返回值:%s' % res)
|
||||
return res
|
||||
|
||||
def action_cancel(self):
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
""",
|
||||
'category': 'sf',
|
||||
'website': 'https://www.sf.jikimo.com',
|
||||
'depends': ['sf_sale', 'sf_dlm', 'sf_manufacturing'],
|
||||
'depends': ['sf_sale', 'sf_dlm', 'sf_manufacturing','jikimo_attachment_viewer'],
|
||||
'data': [
|
||||
'data/stock_data.xml',
|
||||
'views/product_template_management_view.xml',
|
||||
|
||||
@@ -62,22 +62,22 @@ class SfMaintenanceEquipmentOEE(models.Model):
|
||||
("封存(报废)", "封存(报废)")],
|
||||
default='正常', string="机床状态", related='equipment_id.state')
|
||||
|
||||
online_time = fields.Char('开机时长(小时)', reaonly='True')
|
||||
online_time = fields.Char('开机时长(小时)', readonly='True')
|
||||
|
||||
offline_time = fields.Char('关机时长(小时)', reaonly='True')
|
||||
idle_nums = fields.Integer('待机次数', reaonly='True')
|
||||
offline_time = fields.Char('关机时长(小时)', readonly='True')
|
||||
idle_nums = fields.Integer('待机次数', readonly='True')
|
||||
# 待机时长
|
||||
|
||||
idle_time = fields.Char('待机时长(小时)', reaonly='True')
|
||||
idle_time = fields.Char('待机时长(小时)', readonly='True')
|
||||
|
||||
# 待机率
|
||||
idle_rate = fields.Char('待机率(%)', reaonly='True')
|
||||
idle_rate = fields.Char('待机率(%)', readonly='True')
|
||||
|
||||
work_time = fields.Char('加工时长(小时)', reaonly='True')
|
||||
work_rate = fields.Char('可用率(%)', reaonly='True')
|
||||
fault_time = fields.Char('故障时长(小时)', reaonly='True')
|
||||
fault_rate = fields.Char('故障率(%)', reaonly='True')
|
||||
fault_nums = fields.Integer('故障次数', reaonly='True')
|
||||
work_time = fields.Char('加工时长(小时)', readonly='True')
|
||||
work_rate = fields.Char('可用率(%)', readonly='True')
|
||||
fault_time = fields.Char('故障时长(小时)', readonly='True')
|
||||
fault_rate = fields.Char('故障率(%)', readonly='True')
|
||||
fault_nums = fields.Integer('故障次数', readonly='True')
|
||||
|
||||
# 设备故障日志
|
||||
sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志',
|
||||
@@ -367,25 +367,25 @@ class SfMaintenanceEquipmentOEELog(models.Model):
|
||||
[("ZXJGZX", "钻铣加工中心"), ("CXJGZX", "车削加工中心"), ("FHJGZX", "复合加工中心")],
|
||||
default="", string="功能类型")
|
||||
machine_tool_picture = fields.Binary('设备图片')
|
||||
type_id = fields.Many2one('sf.machine_tool.type', '品牌型号', reaonly='True')
|
||||
type_id = fields.Many2one('sf.machine_tool.type', '品牌型号', readonly='True')
|
||||
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
|
||||
("检修", "检修"), ("保养", "保养")], default="", string="实时状态")
|
||||
online_time = fields.Char('开机时长', reaonly='True')
|
||||
online_time = fields.Char('开机时长', readonly='True')
|
||||
|
||||
offline_time = fields.Char('关机时长', reaonly='True')
|
||||
offline_nums = fields.Integer('关机次数', reaonly='True')
|
||||
offline_time = fields.Char('关机时长', readonly='True')
|
||||
offline_nums = fields.Integer('关机次数', readonly='True')
|
||||
# 待机时长
|
||||
|
||||
idle_time = fields.Char('待机时长', reaonly='True')
|
||||
idle_time = fields.Char('待机时长', readonly='True')
|
||||
|
||||
# 待机率
|
||||
idle_rate = fields.Char('待机率', reaonly='True')
|
||||
idle_rate = fields.Char('待机率', readonly='True')
|
||||
|
||||
work_time = fields.Char('加工时长', reaonly='True')
|
||||
work_rate = fields.Char('可用率', reaonly='True')
|
||||
fault_time = fields.Char('故障时长', reaonly='True')
|
||||
fault_rate = fields.Char('故障率', reaonly='True')
|
||||
fault_nums = fields.Integer('故障次数', reaonly='True')
|
||||
work_time = fields.Char('加工时长', readonly='True')
|
||||
work_rate = fields.Char('可用率', readonly='True')
|
||||
fault_time = fields.Char('故障时长', readonly='True')
|
||||
fault_rate = fields.Char('故障率', readonly='True')
|
||||
fault_nums = fields.Integer('故障次数', readonly='True')
|
||||
|
||||
detail_ids = fields.One2many('maintenance.equipment.oee.log.detail', 'log_id', string='日志详情')
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@ access_maintenance_equipment_agv_log,maintenance_equipment_agv_log,model_mainten
|
||||
|
||||
access_maintenance_system_user,equipment.request system user,maintenance.model_maintenance_request,base.group_user,1,1,1,0
|
||||
access_maintenance_wizard_system_user,maintenance.request.wizard system user,model_maintenance_request_wizard,base.group_user,1,1,1,0
|
||||
access_maintenance_sf_group_equipment_user,equipment.request_sf_group_equipment_user,maintenance.model_maintenance_request,sf_group_equipment_user,1,1,1,0
|
||||
access_maintenance_wizard_sf_group_equipment_user,maintenance_wizard_sf_group_equipment_user,model_maintenance_request_wizard,sf_group_equipment_user,1,1,1,0
|
||||
access_maintenance_sf_group_equipment_manager,equipment.request_sf_group_equipment_manager,maintenance.model_maintenance_request,sf_group_equipment_manager,1,1,1,0
|
||||
access_maintenance_wizard_sf_group_equipment_manager,maintenance_wizard_sf_group_equipment_manager,model_maintenance_request_wizard,sf_group_equipment_manager,1,1,1,0
|
||||
|
||||
access_maintenance_equipment_group_plan_dispatch,maintenance.equipment,maintenance.model_maintenance_equipment,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_maintenance_equipment_oee_group_plan_dispatch,maintenance_equipment_oee,model_maintenance_equipment_oee,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
|
@@ -76,33 +76,61 @@
|
||||
<field name="equipment_maintenance_id"/>
|
||||
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='user_id']" position="replace">
|
||||
<field name="user_id" string="维保人"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='close_date']" position="replace">
|
||||
<field name="close_date" attrs="{'invisible': [('done', '!=', True)]}" readonly="True" string="维保日期"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='user_id']" position="replace">
|
||||
<field name="user_id" string="维保人"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='close_date']" position="replace">
|
||||
<field name="close_date" attrs="{'invisible': [('done', '!=', True)]}" readonly="True"
|
||||
string="维保日期"/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='request_date']" position="attributes">
|
||||
<attribute name="string">计划维保日期</attribute>
|
||||
</xpath>
|
||||
|
||||
<sheet>
|
||||
|
||||
<notebook>
|
||||
<page string="维保标准" attrs="{'invisible': [('equipment_maintenance_id', '=', False)]}" context="{'default_standard_id': 'id'}">
|
||||
<page string="维保标准" attrs="{'invisible': [('equipment_maintenance_id', '=', False)]}"
|
||||
context="{'default_standard_id': 'id'}">
|
||||
<field name="maintenance_standards" widget="one2many_list">
|
||||
<tree multi_edit="" editable="">
|
||||
<field name="name" class="table_custom_required"/>
|
||||
<field name="maintenance_standards" class="table_custom_required"/>
|
||||
<field name="images" force_save="1" required="1" class="table_custom_required">
|
||||
<field name="name" class="table_custom_required"/>
|
||||
<field name="maintenance_standards" class="table_custom_required"/>
|
||||
<field name="images" force_save="1" required="1" class="table_custom_required">
|
||||
</field>
|
||||
<field name="remark" class="table_custom_required"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
|
||||
|
||||
</sheet>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="maintenance_request_view_tree_sf" model="ir.ui.view">
|
||||
<field name="name">maintenance.request.view.tree.sf</field>
|
||||
<field name="model">maintenance.request</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='request_date']" position="replace">
|
||||
<field name="request_date" string="计划维保日期"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='user_id']" position="after">
|
||||
<field name="sf_maintenance_type"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="equipment_request_view_search_sf" model="ir.ui.view">
|
||||
<field name="name">maintenance.request.view.search.sf</field>
|
||||
<field name="model">maintenance.request</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//filter[@name='inactive']" position="replace">
|
||||
<filter string="不活跃的" name="inactive" domain="[('archive', '=', True)]"/>
|
||||
<filter string="已归档" name="in_active" domain="[('active', '=', False)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -110,7 +138,7 @@
|
||||
<record id="hr_equipment_request_action1" model="ir.actions.act_window">
|
||||
<field name="name">维保计划</field>
|
||||
<field name="res_model">maintenance.request</field>
|
||||
<field name="view_mode">kanban,tree,form,pivot,graph,calendar</field>
|
||||
<field name="view_mode">tree,kanban,form,pivot,graph,calendar</field>
|
||||
<field name="view_id" ref="maintenance.hr_equipment_request_view_kanban"/>
|
||||
<field name="context">{'default_user_id': uid}</field>
|
||||
<field name="help" type="html">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
""",
|
||||
'category': 'sf',
|
||||
'website': 'https://www.sf.jikimo.com',
|
||||
'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse'],
|
||||
'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse','jikimo_attachment_viewer'],
|
||||
'data': [
|
||||
'data/stock_data.xml',
|
||||
'data/empty_racks_data.xml',
|
||||
@@ -45,6 +45,8 @@
|
||||
'sf_manufacturing/static/src/scss/kanban_change.scss',
|
||||
'sf_manufacturing/static/src/xml/button_show_on_tree.xml',
|
||||
'sf_manufacturing/static/src/js/workpiece_delivery_wizard_confirm.js',
|
||||
'sf_manufacturing/static/src/js/qr.js',
|
||||
'sf_manufacturing/static/src/xml/qr.xml',
|
||||
]
|
||||
|
||||
},
|
||||
|
||||
@@ -141,12 +141,12 @@ class MrpProduction(models.Model):
|
||||
], string='工序状态', default='待装夹')
|
||||
|
||||
# 零件图号
|
||||
part_number = fields.Char('零件图号', readonly=True)
|
||||
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
||||
|
||||
# 上传零件图纸
|
||||
part_drawing = fields.Binary('零件图纸', readonly=True)
|
||||
part_drawing = fields.Binary('零件图纸', related='product_id.machining_drawings', readonly=True)
|
||||
|
||||
quality_standard = fields.Binary('质检标准', readonly=True)
|
||||
quality_standard = fields.Binary('质检标准', related='product_id.quality_standard', readonly=True)
|
||||
|
||||
@api.depends('product_id.manual_quotation')
|
||||
def _compute_manual_quotation(self):
|
||||
@@ -806,6 +806,8 @@ class MrpProduction(models.Model):
|
||||
'date_to': date_planned_end,
|
||||
})
|
||||
# work.write({'date_planned_start': date_planned_start, 'date_planned_finished': date_planned_end})
|
||||
# 设置一个较大的结束时间,防止在设置开始时间时,结束时间小于开始时间
|
||||
work.date_planned_finished = datetime.datetime.today() + datetime.timedelta(days=100)
|
||||
work.date_planned_start = date_planned_start
|
||||
work.date_planned_finished = date_planned_end
|
||||
routing_workcenter = self.env['mrp.routing.workcenter'].sudo().search(
|
||||
|
||||
@@ -59,7 +59,8 @@ class ResMrpWorkOrder(models.Model):
|
||||
compute='_compute_state', store=True,
|
||||
default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True)
|
||||
|
||||
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效')
|
||||
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
|
||||
tracking=True)
|
||||
|
||||
@api.depends('production_id.manual_quotation')
|
||||
def _compute_manual_quotation(self):
|
||||
@@ -305,6 +306,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
is_delivery = fields.Boolean('是否配送完成', default=False)
|
||||
rfid_code = fields.Char('RFID码')
|
||||
rfid_code_old = fields.Char('RFID码(已解除)')
|
||||
is_test_env = fields.Boolean('测试环境', default=False)
|
||||
|
||||
production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id',
|
||||
string='生产线', store=True, tracking=True)
|
||||
@@ -320,6 +322,9 @@ class ResMrpWorkOrder(models.Model):
|
||||
detailed_reason = fields.Text('详细原因')
|
||||
is_rework = fields.Boolean(string='是否返工', default=False)
|
||||
|
||||
def button_change_env(self):
|
||||
self.is_test_env = not self.is_test_env
|
||||
|
||||
@api.constrains('blocked_by_workorder_ids')
|
||||
def _check_no_cyclic_dependencies(self):
|
||||
if self.production_id.state not in ['rework'] and self.state not in ['rework']:
|
||||
@@ -1105,9 +1110,11 @@ class ResMrpWorkOrder(models.Model):
|
||||
if self.routing_type == '装夹预调':
|
||||
# 判断是否有坯料的序列号信息
|
||||
boolean = False
|
||||
if self.production_id.move_raw_ids[0].move_line_ids:
|
||||
if self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name:
|
||||
boolean = True
|
||||
if self.production_id.move_raw_ids:
|
||||
if self.production_id.move_raw_ids[0].move_line_ids:
|
||||
if self.production_id.move_raw_ids[0].move_line_ids:
|
||||
if self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name:
|
||||
boolean = True
|
||||
if not boolean:
|
||||
raise UserError('制造订单【%s】缺少组件的序列号信息!' % self.production_id.name)
|
||||
self.pro_code = self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name
|
||||
@@ -1840,7 +1847,7 @@ class WorkPieceDelivery(models.Model):
|
||||
return is_free
|
||||
else:
|
||||
raise UserError("接驳站暂未反馈站点实时状态,请稍后再试")
|
||||
|
||||
|
||||
def delivery_avg(self):
|
||||
is_agv_task_dispatch = self.env['ir.config_parameter'].sudo().get_param('is_agv_task_dispatch')
|
||||
if is_agv_task_dispatch:
|
||||
|
||||
@@ -16,6 +16,12 @@ from OCC.Extend.DataExchange import write_stl_file
|
||||
class ResProductMo(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
def _get_machining_precision(self):
|
||||
machinings = self.env['sf.machining.accuracy'].sudo().search([])
|
||||
|
||||
list = [(m.sync_id, m.name) for m in machinings]
|
||||
return list
|
||||
|
||||
model_file = fields.Binary('模型文件')
|
||||
categ_type = fields.Selection(string='产品的类别', related='categ_id.type', store=True)
|
||||
model_name = fields.Char('模型名称')
|
||||
@@ -23,12 +29,7 @@ class ResProductMo(models.Model):
|
||||
model_width = fields.Float('模型宽(mm)', digits=(16, 3))
|
||||
model_height = fields.Float('模型高(mm)', digits=(16, 3))
|
||||
model_volume = fields.Float('模型体积(m³)')
|
||||
model_machining_precision = fields.Selection([
|
||||
('0.10', '±0.10mm'),
|
||||
('0.05', '±0.05mm'),
|
||||
('0.03', '±0.03mm'),
|
||||
('0.02', '±0.02mm'),
|
||||
('0.01', '±0.01mm')], string='加工精度')
|
||||
model_machining_precision = fields.Selection(selection=_get_machining_precision, string='加工精度')
|
||||
model_processing_panel = fields.Char('模型加工面板')
|
||||
model_remark = fields.Char('模型备注说明')
|
||||
length = fields.Float('长(mm)', digits=(16, 3))
|
||||
@@ -776,8 +777,6 @@ class ResProductMo(models.Model):
|
||||
part_number = fields.Char(string='零件图号', readonly=True)
|
||||
machining_drawings = fields.Binary('2D加工图纸', readonly=True)
|
||||
quality_standard = fields.Binary('质检标准', readonly=True)
|
||||
machining_drawings_name = fields.Char('2D加工图纸名', readonly=True)
|
||||
quality_standard_name = fields.Char('质检标准名', readonly=True)
|
||||
|
||||
@api.constrains('tool_length')
|
||||
def _check_tool_length_size(self):
|
||||
@@ -839,10 +838,10 @@ class ResProductMo(models.Model):
|
||||
else:
|
||||
return self.env.ref('sf_dlm.product_uom_cubic_millimeter')
|
||||
|
||||
def attachment_update(self, name, res_id, res_field):
|
||||
def attachment_update(self, name, res_id, res_field, mimetype):
|
||||
attachment_info = self.env['ir.attachment'].sudo().search(
|
||||
[('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1)
|
||||
attachment_info.write({'name': name})
|
||||
attachment_info.write({'name': name, 'mimetype': mimetype})
|
||||
|
||||
# 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品
|
||||
def product_create(self, product_id, item, order_id, order_number, i):
|
||||
@@ -882,8 +881,6 @@ class ResProductMo(models.Model):
|
||||
'manual_quotation': item['manual_quotation'] or False,
|
||||
'part_number': item.get('part_number') or '',
|
||||
'active': True,
|
||||
'machining_drawings_name': item['machining_drawings_name'],
|
||||
'quality_standard_name': item['quality_standard_name'],
|
||||
'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode(
|
||||
item['machining_drawings']),
|
||||
'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']),
|
||||
@@ -894,12 +891,12 @@ class ResProductMo(models.Model):
|
||||
vals.update({'taxes_id': [(6, 0, [int(tax_id)])]})
|
||||
copy_product_id.sudo().write(vals)
|
||||
product_id.product_tmpl_id.active = False
|
||||
if item['machining_drawings'] and item['machining_drawings_name']:
|
||||
if item['machining_drawings'] and item['machining_drawings_name'] and item['machining_drawings_mimetype']:
|
||||
self.attachment_update(item['machining_drawings_name'], copy_product_id.product_tmpl_id.id,
|
||||
'machining_drawings')
|
||||
if item['quality_standard'] and item['quality_standard_name']:
|
||||
'machining_drawings', item['machining_drawings_mimetype'])
|
||||
if item['quality_standard'] and item['quality_standard_name'] and item['quality_standard_mimetype']:
|
||||
self.attachment_update(item['quality_standard_name'], copy_product_id.product_tmpl_id.id,
|
||||
'quality_standard')
|
||||
'quality_standard', item['quality_standard_mimetype'])
|
||||
return copy_product_id
|
||||
|
||||
def _get_ids(self, param):
|
||||
|
||||
@@ -272,21 +272,6 @@ class StockRule(models.Model):
|
||||
workorder_duration += workorder.duration_expected
|
||||
|
||||
sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
|
||||
# 根据销售订单号查询快速订单
|
||||
quick_easy_order = self.env['quick.easy.order'].sudo().search([('sale_order_id', '=', sale_order.id)])
|
||||
if quick_easy_order:
|
||||
production.write({'part_number': quick_easy_order.part_drawing_number,
|
||||
'part_drawing': quick_easy_order.machining_drawings})
|
||||
else:
|
||||
production.write({'part_number': production.product_id.part_number,
|
||||
'part_drawing': production.product_id.machining_drawings,
|
||||
'quality_standard': production.product_id.quality_standard})
|
||||
if production.product_id.machining_drawings and production.product_id.machining_drawings_name:
|
||||
self.attachment_update(production.product_id.machining_drawings_name, production.id,
|
||||
'part_drawing')
|
||||
if production.product_id.quality_standard and production.product_id.quality_standard_name:
|
||||
self.attachment_update(production.product_id.quality_standard_name, production.id,
|
||||
'quality_standard')
|
||||
if sale_order:
|
||||
# sale_order.write({'schedule_status': 'to schedule'})
|
||||
self.env['sf.production.plan'].sudo().with_company(company_id).create({
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<data noupdate="1">
|
||||
<record id="group_show_button" model="res.groups">
|
||||
<field name="name">演示模式</field>
|
||||
<field name="category_id" ref="base.module_category_hidden"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
</odoo>
|
||||
|
||||
|
||||
115
sf_manufacturing/static/src/js/qr.js
Normal file
115
sf_manufacturing/static/src/js/qr.js
Normal file
@@ -0,0 +1,115 @@
|
||||
/** @odoo-module **/
|
||||
import { registry } from '@web/core/registry';
|
||||
import { Component } from '@odoo/owl';
|
||||
|
||||
class QRCodeWidget extends Component {
|
||||
// 初始化组件
|
||||
setup() {
|
||||
console.log('QRCodeWidget setup');
|
||||
this.qrCodeValue = ''; // 初始化为空字符串,用于存储条码
|
||||
this.inputBuffer = ''; // 存储临时输入的字符
|
||||
this.inputTimer = null; // 定时器
|
||||
|
||||
// 显式绑定上下文
|
||||
this.onGlobalKeyDown = this.onGlobalKeyDown.bind(this);
|
||||
window.addEventListener('keydown', this.onGlobalKeyDown);
|
||||
}
|
||||
|
||||
// 清理事件监听器,防止内存泄漏
|
||||
willUnmount() {
|
||||
window.removeEventListener('keydown', this.onGlobalKeyDown);
|
||||
if (this.inputTimer) {
|
||||
clearTimeout(this.inputTimer);
|
||||
}
|
||||
}
|
||||
|
||||
// 全局键盘事件监听器
|
||||
onGlobalKeyDown(event) {
|
||||
|
||||
// 如果是Tab键,表示扫码输入结束
|
||||
if (event.key === 'Tab' || event.key === 'Enter') {
|
||||
this.qrCodeValue = this.inputBuffer; // 完整条码赋值
|
||||
console.log('完整条码:', this.qrCodeValue);
|
||||
this.onQRCodeChange(this.qrCodeValue); // 调用父组件的 onQRCodeChange 方法
|
||||
this.inputBuffer = ''; // 清空临时缓冲区
|
||||
event.preventDefault(); // 阻止Tab键的默认行为
|
||||
return;
|
||||
}
|
||||
|
||||
// 只处理可打印字符
|
||||
if (event.key.length === 1) {
|
||||
this.inputBuffer += event.key; // 添加到缓冲区
|
||||
// console.log('当前缓冲区:', this.inputBuffer);
|
||||
|
||||
// 清除之前的定时器,重新开始计时
|
||||
if (this.inputTimer) {
|
||||
clearTimeout(this.inputTimer);
|
||||
}
|
||||
|
||||
// 启动一个定时器,如果500ms内没有新的输入,则认为条码输入完成
|
||||
this.inputTimer = setTimeout(() => {
|
||||
this.qrCodeValue = this.inputBuffer;
|
||||
// console.log('定时器触发,完整条码:', this.qrCodeValue);
|
||||
this.inputBuffer = ''; // 清空缓冲区
|
||||
}, 500); // 可以根据需要调整时间
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 处理二维码输入变更
|
||||
async onQRCodeChange(qrCodeValue) {
|
||||
console.log('onQRCodeChange二维码输入变更', qrCodeValue); // 检查二维码的输入是否被捕获
|
||||
|
||||
if (qrCodeValue) {
|
||||
// console.log('二维码输入变更');
|
||||
try {
|
||||
// 发起 RPC 请求
|
||||
const result = await this.env.services.rpc('/web/dataset/call_kw', {
|
||||
model: 'mrp.workorder',
|
||||
method: 'search_read',
|
||||
args: [
|
||||
[['rfid_code', '=', qrCodeValue]], // 查询条件
|
||||
['id'] // 返回的字段
|
||||
],
|
||||
kwargs: {}
|
||||
});
|
||||
|
||||
if (result.length > 0) {
|
||||
console.log('该二维码对应的工单存在!');
|
||||
} else {
|
||||
console.log('未找到对应的工单。');
|
||||
|
||||
const routingTypeField = document.querySelector('[name="routing_type"]');
|
||||
if (routingTypeField) {
|
||||
let fieldValue = routingTypeField.querySelector('span').getAttribute('raw-value');
|
||||
console.log('Routing Type Value:', fieldValue);
|
||||
// 清理多余的引号
|
||||
fieldValue = fieldValue ? fieldValue.replace(/["]+/g, '') : null;
|
||||
console.log(fieldValue);
|
||||
|
||||
if (fieldValue && fieldValue === '装夹预调') {
|
||||
// console.log('routing_type 为装夹预调');
|
||||
|
||||
// 检查 RFID 值
|
||||
if (!qrCodeValue || qrCodeValue.length <= 3) return;
|
||||
|
||||
// 查找 name="button_start" 按钮并触发点击事件
|
||||
const startButton = document.querySelector('[name="button_start"]');
|
||||
if (startButton) {
|
||||
startButton.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('查询工单时出错:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回模板名称
|
||||
static template = 'sf_manufacturing.QRCodeWidgetTemplate';
|
||||
}
|
||||
|
||||
// 将自定义字段注册到字段注册表
|
||||
registry.category('fields').add('qrcode_widget', QRCodeWidget);
|
||||
12
sf_manufacturing/static/src/xml/qr.xml
Normal file
12
sf_manufacturing/static/src/xml/qr.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<t t-name="sf_manufacturing.QRCodeWidgetTemplate" owl="1">
|
||||
<!-- <div> -->
|
||||
<!-- <input type="text" t-att-value="props.value" placeholder="Scan QR code here" /> -->
|
||||
<!-- </div> -->
|
||||
<div t-esc="props.value">
|
||||
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
<field name="target">current</field>
|
||||
<field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>
|
||||
<field name="context">{'search_default_product': 1, 'search_default_workcenter_id':
|
||||
active_id,'search_default_filter_order_warning':1,'search_default_filter_order_overdue':1}
|
||||
active_id,'search_default_filter_order_warning':1,'search_default_filter_order_overdue':1,'search_default_filter_order_normal':1}
|
||||
</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_workorder">
|
||||
@@ -125,9 +125,9 @@
|
||||
<field name="model">mrp.workorder</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form" position="inside">
|
||||
<script src="sf_manufacturing/static/src/js/customRFID.js"/>
|
||||
</xpath>
|
||||
<!-- <xpath expr="//form" position="inside"> -->
|
||||
<!-- <script src="sf_manufacturing/static/src/js/customRFID.js"/> -->
|
||||
<!-- </xpath> -->
|
||||
<xpath expr="//header/field[@name='state']" position="replace">
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/>
|
||||
@@ -225,6 +225,7 @@
|
||||
<xpath expr="//label[1]" position="before">
|
||||
<!-- -->
|
||||
<field name="production_id" invisible="0"/>
|
||||
<field name="routing_type" string="工单类型" readonly="1"/>
|
||||
<field name="duration_expected" invisible="1"/>
|
||||
<field name="date_planned_start" invisible="1"/>
|
||||
<field name="date_planned_finished" invisible="1"/>
|
||||
@@ -246,11 +247,24 @@
|
||||
<field name='process_state' invisible="1"/>
|
||||
<field name='tag_type' readonly="1" attrs='{"invisible": [("tag_type","=",False)]}'
|
||||
decoration-danger="tag_type == '重新加工'"/>
|
||||
<field name="rfid_code" force_save="1" readonly="0" cache="True"
|
||||
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
|
||||
<field name="is_test_env" invisible="1"/>
|
||||
<field name="rfid_code" force_save="1" readonly="1" cache="True"
|
||||
attrs="{'invisible': [('rfid_code_old', '!=', False)]}" widget='qrcode_widget'/>
|
||||
<field name="rfid_code" string="RFID码(手动输入框)" force_save="1" readonly="0" cache="True"
|
||||
attrs="{'invisible': ['|',('rfid_code_old', '!=', False), ('is_test_env', '=', False)]}"/>
|
||||
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
|
||||
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//header" position="inside">
|
||||
<div class="o_statusbar_buttons"><button name="button_change_env"
|
||||
type="object"
|
||||
string="演示模式"
|
||||
class="btn-primary"
|
||||
groups="sf_manufacturing.group_show_button"/>
|
||||
</div>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//form//sheet//group//group//div[2]" position="replace">
|
||||
</xpath>
|
||||
<xpath expr="//form//sheet//group//group//div[1]" position="after">
|
||||
@@ -466,6 +480,15 @@
|
||||
<field name='X_deviation_angle' readonly="1"/>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<page string="2D加工图纸" attrs="{'invisible': [('routing_type','!=','装夹预调')]}">
|
||||
<field name="machining_drawings" widget="adaptive_viewer"/>
|
||||
</page>
|
||||
|
||||
<page string="质检标准" attrs="{'invisible': [('routing_type','!=','装夹预调')]}">
|
||||
<field name="quality_standard" widget="adaptive_viewer"/>
|
||||
</page>
|
||||
|
||||
<page string="工件配送"
|
||||
attrs="{'invisible': [('routing_type','!=','装夹预调')]}">
|
||||
<field name="workpiece_delivery_ids">
|
||||
@@ -519,6 +542,13 @@
|
||||
<!-- attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>-->
|
||||
<!-- </div>-->
|
||||
</page>
|
||||
<page string="2D加工图纸" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||
<field name="machining_drawings" widget="adaptive_viewer"/>
|
||||
</page>
|
||||
|
||||
<page string="质检标准" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||
<field name="quality_standard" widget="adaptive_viewer"/>
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="//page[1]" position="before">
|
||||
<page string="CNC程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||
@@ -589,18 +619,6 @@
|
||||
mrp.group_mrp_manager,sf_base.group_sf_mrp_manager,sf_base.group_sf_equipment_user,sf_base.group_sf_order_user
|
||||
</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//sheet//notebook" position="inside">
|
||||
<page string="2D加工图纸">
|
||||
<field name="machining_drawings" widget="adaptive_viewer"
|
||||
attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="//sheet//notebook" position="inside">
|
||||
<page string="质检标准">
|
||||
<field name="quality_standard" widget="adaptive_viewer"
|
||||
attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -641,6 +659,7 @@
|
||||
<separator/>
|
||||
<filter string="预警" name="filter_order_warning" domain="[('delivery_warning', '=', 'warning')]"/>
|
||||
<filter string="逾期" name="filter_order_overdue" domain="[('delivery_warning', '=', 'overdue')]"/>
|
||||
<filter string="正常" name="filter_order_normal" domain="[('delivery_warning', '=', 'normal')]"/>
|
||||
<separator/>
|
||||
</xpath>
|
||||
</field>
|
||||
|
||||
@@ -13,6 +13,19 @@
|
||||
<field name="active" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.cron" id="ir_cron_sale_order_recover_time_warning">
|
||||
<field name="name">检查销售订单是否完成并恢复正常时效</field>
|
||||
<field name="model_id" ref="model_sale_order"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._recover_sale_time_warning_func()</field>
|
||||
<field name="interval_number">10</field>
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="active" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.cron" id="ir_cron_mrp_workorder_overdue_warning">
|
||||
<field name="name">检查工单是否已逾期预警和逾期</field>
|
||||
<field name="model_id" ref="model_mrp_workorder"/>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 销售订单逾期预警
|
||||
事项:共有[{{warning_num}}]({{url}})个销售订单有逾期风险
|
||||
事项:[共有{{warning_num}}个销售订单有逾期风险]({{url}})
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">urgent</field>
|
||||
<field name="content">### 销售订单已逾期提醒
|
||||
事项:共有[{{overdue_num}}]({{url}})个销售订单已逾期
|
||||
事项:[共有{{overdue_num}}个销售订单已逾期]({{url}})
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
<field name="send_type">timing</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 工单逾期预警
|
||||
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
|
||||
事项:[共有{{warning_num}}个工单有逾期风险]({{url}})</field>
|
||||
</record>
|
||||
|
||||
<record id="template_mrp_workorder_pre_overdue" model="jikimo.message.template">
|
||||
@@ -109,7 +109,7 @@
|
||||
<field name="send_type">timing</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 工单已逾期提醒
|
||||
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
|
||||
事项:[共有{{overdue_num}}个工单已逾期]({{url}})</field>
|
||||
</record>
|
||||
|
||||
<record id="template_mrp_workorder_cnc_overdue_warning" model="jikimo.message.template">
|
||||
@@ -121,7 +121,7 @@
|
||||
<field name="send_type">timing</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 工单逾期预警
|
||||
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
|
||||
事项:[共有{{warning_num}}个工单有逾期风险]({{url}})</field>
|
||||
</record>
|
||||
|
||||
<record id="template_mrp_workorder_cnc_overdue" model="jikimo.message.template">
|
||||
@@ -133,7 +133,7 @@
|
||||
<field name="send_type">timing</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 工单已逾期提醒
|
||||
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
|
||||
事项:[共有{{overdue_num}}个工单已逾期]({{url}})</field>
|
||||
</record>
|
||||
|
||||
<record id="template_mrp_workorder_unclamp_overdue_warning" model="jikimo.message.template">
|
||||
@@ -145,7 +145,7 @@
|
||||
<field name="send_type">timing</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 工单逾期预警
|
||||
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
|
||||
事项:[共有{{warning_num}}个工单有逾期风险]({{url}})</field>
|
||||
</record>
|
||||
|
||||
<record id="template_mrp_workorder_unclamp_overdue" model="jikimo.message.template">
|
||||
@@ -157,7 +157,7 @@
|
||||
<field name="send_type">timing</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 工单已逾期提醒
|
||||
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
|
||||
事项:[共有{{overdue_num}}个工单已逾期]({{url}})</field>
|
||||
</record>
|
||||
|
||||
<record id="template_mrp_workorder_surface_overdue_warning" model="jikimo.message.template">
|
||||
@@ -169,7 +169,7 @@
|
||||
<field name="send_type">timing</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 工单逾期预警
|
||||
事项:共有[{{warning_num}}]({{url}})工单有逾期风险</field>
|
||||
事项:[共有{{warning_num}}个工单有逾期风险]({{url}})</field>
|
||||
</record>
|
||||
|
||||
<record id="template_mrp_workorder_surface_overdue" model="jikimo.message.template">
|
||||
@@ -181,7 +181,7 @@
|
||||
<field name="send_type">timing</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 工单已逾期提醒
|
||||
事项:共有[{{overdue_num}}]({{url}})工单已逾期</field>
|
||||
事项:[共有{{overdue_num}}个工单已逾期]({{url}})</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 待质量判定提醒
|
||||
事项:共有[{{judge_num}}]({{url}})个工单需判定质量结果</field>
|
||||
事项:[共有{{judge_num}}个工单需判定质量结果]({{url}})</field>
|
||||
</record>
|
||||
<record id="template_maintenance_logs" model="jikimo.message.template">
|
||||
<field name="name">设备故障</field>
|
||||
|
||||
@@ -34,18 +34,19 @@ class SFMessageSale(models.Model):
|
||||
picking_id.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id).ids
|
||||
purchase_order_id.extend(purchase_order_ids)
|
||||
if purchase_order_id:
|
||||
purchase_order_list = self.env['purchase.order'].search([('id', 'in', purchase_order_id)])
|
||||
purchase_order_list = self.env['purchase.order'].sudo().search([('id', 'in', purchase_order_id)])
|
||||
for purchase_order_info in purchase_order_list:
|
||||
purchase_order_info.add_queue('坯料采购提醒')
|
||||
except Exception as e:
|
||||
logging.info('add_queue error:%s' % e)
|
||||
logging.info('action_confirm res:%s' % res)
|
||||
return res
|
||||
|
||||
# 继承并重写jikimo.message.dispatch的_get_message()
|
||||
def _get_message(self, message_queue_ids):
|
||||
contents = []
|
||||
bussiness_node = None
|
||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
current_time_strf = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
current_time = self.env['sf.sync.common'].sudo().get_add_time(current_time_strf)
|
||||
current_time_datetime = datetime.strptime(current_time, '%Y-%m-%d %H:%M:%S')
|
||||
@@ -60,7 +61,7 @@ class SFMessageSale(models.Model):
|
||||
contents.append(content)
|
||||
elif item.message_template_id.bussiness_node_id.name == '确认接单':
|
||||
content = super(SFMessageSale, self)._get_message(item)
|
||||
sale_order_line = self.env['sale.order.line'].search([('order_id', '=', int(item.res_id))])
|
||||
sale_order_line = self.env['sale.order.line'].sudo().search([('order_id', '=', int(item.res_id))])
|
||||
product = sale_order_line[0].product_id.name if len(sale_order_line) == 1 else '%s...' % \
|
||||
sale_order_line[
|
||||
0].product_id.name
|
||||
@@ -100,42 +101,49 @@ class SFMessageSale(models.Model):
|
||||
|
||||
# # 销售订单逾期预警和已逾期
|
||||
def _overdue_or_warning_func(self):
|
||||
today = datetime.today().date()
|
||||
deadline_check = today + timedelta(days=1)
|
||||
logging.info(f"today: {today}, deadline_check: {deadline_check}")
|
||||
current_time_strf = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
current_time = self.env['sf.sync.common'].sudo().get_add_time(current_time_strf)
|
||||
today_str = datetime.strptime(current_time, '%Y-%m-%d %H:%M:%S')
|
||||
today = today_str.strftime("%Y-%m-%d")
|
||||
# 计算下一天的日期
|
||||
deadline_check_str = today_str + timedelta(days=1)
|
||||
deadline_check = deadline_check_str.strftime("%Y-%m-%d")
|
||||
logging.info(
|
||||
f"today: {today}, deadline_check: {deadline_check},current_time_strf: {current_time_strf}, current_time: {current_time}'")
|
||||
sale_order = self.sudo().search(
|
||||
[('state', 'in', ['sale']), ('deadline_of_delivery', '!=', False), ('delivery_status', '!=', 'full')])
|
||||
for item in sale_order:
|
||||
production = self.env['mrp.production'].search([('origin', '=', item.name)])
|
||||
production = self.env['mrp.production'].sudo().search([('origin', '=', item.name)])
|
||||
production_not_done = production.filtered(lambda p: p.state not in ['done', 'scrap', 'cancel'])
|
||||
production_done_count = len(production.filtered(lambda p: p.state in ['done', 'scrap', 'cancel']))
|
||||
deadline_of_delivery = item.deadline_of_delivery.strftime("%Y-%m-%d")
|
||||
if (len(production_not_done) >= 1 and len(production_not_done) != item.mrp_production_count) or len(
|
||||
production_not_done) != production_done_count:
|
||||
logging.info("-----不等于----")
|
||||
logging.info(f"name: {item.name}")
|
||||
logging.info(
|
||||
f"production_not_done: {len(production_not_done)}, production_done_count: {production_done_count}")
|
||||
logging.info(f"deadline_of_delivery: {item.deadline_of_delivery}")
|
||||
if deadline_check == item.deadline_of_delivery and item.delivery_warning not in ['warning']:
|
||||
# logging.info("-----不等于----")
|
||||
# logging.info(f"name: {item.name}")
|
||||
# logging.info(
|
||||
# f"production_not_done: {len(production_not_done)}, production_done_count: {production_done_count}")
|
||||
# logging.info(f"deadline_of_delivery: {item.deadline_of_delivery}")
|
||||
if deadline_check == deadline_of_delivery and item.delivery_warning not in ['warning']:
|
||||
item.delivery_warning = 'warning'
|
||||
elif today >= item.deadline_of_delivery and item.delivery_warning not in ['overdue']:
|
||||
elif today >= deadline_of_delivery and item.delivery_warning not in ['overdue']:
|
||||
item.delivery_warning = 'overdue'
|
||||
elif production_done_count == item.mrp_production_count:
|
||||
logging.info("-----等于----")
|
||||
logging.info(f"name: {item.name}")
|
||||
logging.info(
|
||||
f"production_not_done: {len(production_not_done)}, production_done_count: {production_done_count}")
|
||||
logging.info(f"deadline_of_delivery: {item.deadline_of_delivery}")
|
||||
# logging.info("-----等于----")
|
||||
# logging.info(f"name: {item.name}")
|
||||
# logging.info(
|
||||
# f"production_not_done: {len(production_not_done)}, production_done_count: {production_done_count}")
|
||||
# logging.info(f"deadline_of_delivery: {item.deadline_of_delivery}")
|
||||
if item.delivery_status in ['pending', 'partial']:
|
||||
if deadline_check == item.deadline_of_delivery and item.delivery_warning not in ['warning']:
|
||||
if deadline_check == deadline_of_delivery and item.delivery_warning not in ['warning']:
|
||||
item.delivery_warning = 'warning'
|
||||
elif today >= item.deadline_of_delivery and item.delivery_warning not in ['overdue']:
|
||||
elif today >= deadline_of_delivery and item.delivery_warning not in ['overdue']:
|
||||
item.delivery_warning = 'overdue'
|
||||
else:
|
||||
logging.info("-----1111111----")
|
||||
logging.info(f"name: {item.name}")
|
||||
logging.info(
|
||||
f"production_not_done: {len(production_not_done)}, production_done_count: {production_done_count}")
|
||||
# logging.info("-----1111111----")
|
||||
# logging.info(f"name: {item.name}")
|
||||
# logging.info(
|
||||
# f"production_not_done: {len(production_not_done)}, production_done_count: {production_done_count}")
|
||||
continue
|
||||
# 获取业务节点
|
||||
business_node_ids = {
|
||||
@@ -146,11 +154,11 @@ class SFMessageSale(models.Model):
|
||||
for wo in overdue_orders:
|
||||
business_node_id = business_node_ids.get(wo.delivery_warning)
|
||||
if business_node_id:
|
||||
message_template = self.env["jikimo.message.template"].search([
|
||||
message_template = self.env["jikimo.message.template"].sudo().search([
|
||||
("model", "=", self._name),
|
||||
("bussiness_node_id", "=", business_node_id)
|
||||
], limit=1)
|
||||
sale_order_has = self.env['jikimo.message.queue'].search([
|
||||
sale_order_has = self.env['jikimo.message.queue'].sudo().search([
|
||||
('res_id', '=', wo.id),
|
||||
('message_status', '=', 'pending'),
|
||||
('message_template_id', '=', message_template.id)
|
||||
@@ -158,3 +166,32 @@ class SFMessageSale(models.Model):
|
||||
if not sale_order_has:
|
||||
message_name = '销售订单逾期预警' if wo.delivery_warning == 'warning' else '销售订单已逾期'
|
||||
wo.add_queue(message_name)
|
||||
if wo.delivery_warning == 'overdue':
|
||||
# 把消息队列中销售订单预警的状态改为取消发送
|
||||
business_node_id_warning = business_node_ids['warning']
|
||||
if business_node_id_warning:
|
||||
message_template_warning = self.env["jikimo.message.template"].search([
|
||||
("model", "=", self._name),
|
||||
("bussiness_node_id", "=", business_node_id_warning)
|
||||
], limit=1)
|
||||
if message_template_warning:
|
||||
sale_order_warning = self.env['jikimo.message.queue'].search([
|
||||
('res_id', '=', wo.id),
|
||||
('message_status', '=', 'pending'),
|
||||
('message_template_id', '=', message_template_warning.id)
|
||||
])
|
||||
if sale_order_warning:
|
||||
logging.info('取消发送:%s' % sale_order_warning)
|
||||
sale_order_warning.write({'message_status': 'cancel'})
|
||||
|
||||
def _recover_sale_time_warning_func(self):
|
||||
sale_order_done = self.sudo().search([('state', 'in', ['sale']), ('delivery_status', '=', 'full')])
|
||||
sale_order_overdue = sale_order_done.filtered(lambda x: x.delivery_warning in ['overdue', 'warning'])
|
||||
if sale_order_overdue:
|
||||
sale_order_overdue.write({'delivery_warning': 'normal'})
|
||||
message_queue_ids = self.env["jikimo.message.queue"].sudo().search([
|
||||
("message_status", "=", "pending"),
|
||||
("res_id", "in", [item.id for item in sale_order_overdue])
|
||||
])
|
||||
if message_queue_ids:
|
||||
message_queue_ids.write({'message_status': 'cancel'})
|
||||
|
||||
@@ -29,14 +29,14 @@ class SFMessageStockPicking(models.Model):
|
||||
[('origin', '=', record.origin), ('state', '!=', 'done'),
|
||||
('picking_type_id.sequence_code', '=', 'SFP')])
|
||||
if not stock_picking_sfp:
|
||||
stock_picking_send = self.env["jikimo.message.queue"].search([('res_id', '=', record.id)])
|
||||
stock_picking_send = self.env["jikimo.message.queue"].sudo().search([('res_id', '=', record.id)])
|
||||
if not stock_picking_send:
|
||||
record.add_queue('订单发货提醒')
|
||||
|
||||
def deal_stock_picking_sfp(self, message_queue_id): # 处理订单发货提醒
|
||||
content = None
|
||||
stock_picking = self.env['stock.picking'].search([('id', '=', int(message_queue_id.res_id))])
|
||||
stock_picking_out = self.env['stock.picking'].search(
|
||||
stock_picking = self.env['stock.picking'].sudo().search([('id', '=', int(message_queue_id.res_id))])
|
||||
stock_picking_out = self.env['stock.picking'].sudo().search(
|
||||
[('origin', '=', stock_picking.origin), ('state', '=', 'assigned'),
|
||||
('picking_type_id.sequence_code', '=', 'OUT')])
|
||||
if stock_picking_out and len(stock_picking_out) > 0:
|
||||
@@ -54,10 +54,10 @@ class SFMessageStockPicking(models.Model):
|
||||
i = 0
|
||||
if message_queue_id.message_template_id.name == '坯料发料提醒':
|
||||
content = message_queue_id.message_template_id.content
|
||||
stock_picking_line = self.env['stock.picking'].search([('id', '=', int(message_queue_id.res_id))])
|
||||
mrp_production_info = self.env['mrp.production'].search(
|
||||
stock_picking_line = self.env['stock.picking'].sudo().search([('id', '=', int(message_queue_id.res_id))])
|
||||
mrp_production_info = self.env['mrp.production'].sudo().search(
|
||||
[('name', '=', stock_picking_line.origin)])
|
||||
mrp_production_list = self.env['mrp.production'].search(
|
||||
mrp_production_list = self.env['mrp.production'].sudo().search(
|
||||
[('product_id', '=', mrp_production_info.product_id.id)])
|
||||
for mrp_production_line in mrp_production_list:
|
||||
picking_ids = mrp_production_line.picking_ids
|
||||
@@ -87,9 +87,9 @@ class SFMessageStockPicking(models.Model):
|
||||
return super(SFMessageStockPicking, self).get_special_url(id, tmplate_name, special_name, model_id)
|
||||
|
||||
def request_url(self):
|
||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
action_id = self.env.ref('stock.stock_picking_type_action').id
|
||||
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id
|
||||
menu_id = self.env['ir.model.data'].sudo().search([('name', '=', 'module_theme_treehouse')]).id
|
||||
# 查询参数
|
||||
params = {'menu_id': menu_id, 'action': action_id, 'model': 'stock.picking',
|
||||
'view_type': 'kanban'}
|
||||
@@ -100,9 +100,9 @@ class SFMessageStockPicking(models.Model):
|
||||
return full_url
|
||||
|
||||
def request_url1(self, id):
|
||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
action_id = self.env.ref('stock.action_picking_tree_all').id
|
||||
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id
|
||||
menu_id = self.env['ir.model.data'].sudo().search([('name', '=', 'module_theme_treehouse')]).id
|
||||
# 查询参数
|
||||
params = {'id': id, 'menu_id': menu_id, 'action': action_id, 'model': 'stock.picking',
|
||||
'view_type': 'form'}
|
||||
|
||||
@@ -26,7 +26,7 @@ class SFMessageWork(models.Model):
|
||||
contents = []
|
||||
product_id = []
|
||||
bussiness_node = None
|
||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
current_time_strf = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
current_time = self.env['sf.sync.common'].sudo().get_add_time(current_time_strf)
|
||||
current_time_datetime = datetime.strptime(current_time, '%Y-%m-%d %H:%M:%S')
|
||||
@@ -39,8 +39,8 @@ class SFMessageWork(models.Model):
|
||||
for message_queue_id in message_queue_ids:
|
||||
if message_queue_id.message_template_id.name == '工单已下发通知':
|
||||
content = message_queue_id.message_template_id.content
|
||||
mrp_workorder_line = self.env['mrp.workorder'].search([('id', '=', int(message_queue_id.res_id))])
|
||||
mrp_workorder_list = self.env['mrp.workorder'].search(
|
||||
mrp_workorder_line = self.env['mrp.workorder'].sudo().search([('id', '=', int(message_queue_id.res_id))])
|
||||
mrp_workorder_list = self.env['mrp.workorder'].sudo().search(
|
||||
[('product_id', '=', mrp_workorder_line.product_id.id), ('state', '=', 'ready'),
|
||||
('routing_type', '=', '装夹预调')])
|
||||
if len(mrp_workorder_list) > 0 and mrp_workorder_line.product_id.id not in product_id:
|
||||
@@ -61,20 +61,32 @@ class SFMessageWork(models.Model):
|
||||
second=0,
|
||||
microsecond=0
|
||||
)
|
||||
logging.info(current_time)
|
||||
logging.info(target_time)
|
||||
logging.info(target_time - time_range)
|
||||
logging.info(target_time + time_range)
|
||||
# logging.info(current_time)
|
||||
# logging.info(target_time)
|
||||
# logging.info(target_time - time_range)
|
||||
# logging.info(target_time + time_range)
|
||||
if target_time - time_range <= current_time_datetime <= target_time + time_range:
|
||||
search_condition = [
|
||||
('delivery_warning', '=', 'warning')] if bussiness_node in template_names['预警'] else [
|
||||
('delivery_warning', '=', 'overdue')]
|
||||
record = self.sudo().search(search_condition + [('id', '=', int(item.res_id))])
|
||||
record = self.sudo().search(search_condition + [('id', '=', int(message_queue_id.res_id))])
|
||||
if record:
|
||||
bussiness_node = item.bussiness_node_id.name
|
||||
# 分割业务节点名称,提取出业务节点关键字
|
||||
business_node_key = bussiness_node.split('工单')[0].strip()
|
||||
workcenter_mapping = {
|
||||
'装夹预调': '工件装夹',
|
||||
'CNC加工': '自动生产',
|
||||
'解除装夹': '工件拆卸',
|
||||
'表面工艺': '表面工艺外协',
|
||||
}
|
||||
workcenter_name = workcenter_mapping.get(business_node_key)
|
||||
active_id = self.env['mrp.workcenter'].search([('name', 'ilike', workcenter_name)],
|
||||
limit=1).id
|
||||
i += 1
|
||||
if i >= 1:
|
||||
action_id = self.env.ref('sf_message.mrp_workorder_action_notify').id
|
||||
url_with_id = f"{url}/web#view_type=list&action={action_id}"
|
||||
url_with_id = f"{url}/web#view_type=list&action={action_id}&active_id={active_id}"
|
||||
content_template = content.replace('{{url}}', url_with_id)
|
||||
if bussiness_node in template_names['预警']:
|
||||
content = content_template.replace('{{warning_num}}', str(i))
|
||||
@@ -84,12 +96,13 @@ class SFMessageWork(models.Model):
|
||||
return contents
|
||||
|
||||
def request_url(self):
|
||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
action_id = self.env.ref('sf_message.mrp_workorder_action_notify').id
|
||||
menu_id = self.env['ir.model.data'].search([('name', '=', 'module_stock_dropshipping')]).id
|
||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
action_id = self.env.ref('sf_message.mrp_workorder_issued_action').id
|
||||
menu_id = self.env['ir.model.data'].sudo().search([('name', '=', 'module_stock_dropshipping')]).id
|
||||
active_id = self.env['mrp.workcenter'].sudo().search([('name', '=', '工件装夹中心')]).id
|
||||
# 查询参数
|
||||
params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder',
|
||||
'view_type': 'list', 'active_id': 1}
|
||||
'view_type': 'list', 'active_id': active_id}
|
||||
# 拼接查询参数
|
||||
query_string = urlencode(params)
|
||||
# 拼接URL
|
||||
@@ -97,7 +110,8 @@ class SFMessageWork(models.Model):
|
||||
return full_url
|
||||
|
||||
def _overdue_or_warning_func(self):
|
||||
workorders = self.env['mrp.workorder'].search([("state", "in", ["ready", "progress", "to be detected"])])
|
||||
workorders = self.env['mrp.workorder'].search(
|
||||
[("state", "in", ["ready", "progress", "to be detected"]), ('schedule_state', '=', '已排')])
|
||||
grouped_workorders = {}
|
||||
for workorder in workorders:
|
||||
routing_type = workorder.routing_type
|
||||
@@ -116,21 +130,25 @@ class SFMessageWork(models.Model):
|
||||
date_planned_finished = datetime.strptime(date_planned_finished_str, '%Y-%m-%d %H:%M:%S')
|
||||
twelve_hours_ago = current_time_datetime - timedelta(hours=12)
|
||||
if current_time_datetime >= date_planned_finished and item.delivery_warning not in ['overdue']:
|
||||
logging.info("------overdue-------")
|
||||
logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, "
|
||||
f"Planned Finish: {date_planned_finished}")
|
||||
# logging.info("------overdue-------")
|
||||
# logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, "
|
||||
# f"Planned Finish: {date_planned_finished}")
|
||||
item.delivery_warning = 'overdue'
|
||||
elif twelve_hours_ago <= current_time_datetime <= date_planned_finished and item.delivery_warning not in [
|
||||
'warning']:
|
||||
logging.info("------warning-------")
|
||||
logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, "
|
||||
f"Planned Finish: {date_planned_finished}")
|
||||
# logging.info("------warning-------")
|
||||
# logging.info(f"Workorder: {item.production_id.name}, Current Time: {current_time_datetime}, "
|
||||
# f"Planned Finish: {date_planned_finished}")
|
||||
item.delivery_warning = 'warning'
|
||||
business_node_ids = {
|
||||
'装夹预调': self.env.ref('sf_message.bussiness_mrp_workorder_pre_overdue_warning').id,
|
||||
'CNC加工': self.env.ref('sf_message.bussiness_mrp_workorder_cnc_overdue_warning').id,
|
||||
'解除装夹': self.env.ref('sf_message.bussiness_mrp_workorder_unclamp_overdue_warning').id,
|
||||
'表面工艺': self.env.ref('sf_message.bussiness_mrp_workorder_surface_overdue_warning').id,
|
||||
'装夹预调_overdue': self.env.ref('sf_message.bussiness_mrp_workorder_pre_overdue').id,
|
||||
'装夹预调_warning': self.env.ref('sf_message.bussiness_mrp_workorder_pre_overdue_warning').id,
|
||||
'CNC加工_overdue': self.env.ref('sf_message.bussiness_mrp_workorder_cnc_overdue').id,
|
||||
'CNC加工_warning': self.env.ref('sf_message.bussiness_mrp_workorder_cnc_overdue_warning').id,
|
||||
'解除装夹_overdue': self.env.ref('sf_message.bussiness_mrp_workorder_unclamp_overdue').id,
|
||||
'解除装夹_warning': self.env.ref('sf_message.bussiness_mrp_workorder_unclamp_overdue_warning').id,
|
||||
'表面工艺_overdue': self.env.ref('sf_message.bussiness_mrp_workorder_surface_overdue').id,
|
||||
'表面工艺_warning': self.env.ref('sf_message.bussiness_mrp_workorder_surface_overdue_warning').id,
|
||||
}
|
||||
message_templates = {key: self.env["jikimo.message.template"].sudo().search([
|
||||
("model", "=", self._name),
|
||||
@@ -138,13 +156,17 @@ class SFMessageWork(models.Model):
|
||||
]) for key in business_node_ids}
|
||||
for item in orders:
|
||||
if item.delivery_warning in ['overdue', 'warning']:
|
||||
bussiness_node_id = business_node_ids.get(item.routing_type)
|
||||
if bussiness_node_id and message_templates[item.routing_type]:
|
||||
message_queue_ids = self.env["jikimo.message.queue"].sudo().search([
|
||||
("message_template_id", "=", message_templates[item.routing_type].id),
|
||||
("message_status", "=", "pending"),
|
||||
("res_id", "=", item.id)
|
||||
])
|
||||
warning_type = 'warning' if item.delivery_warning == 'warning' else 'overdue'
|
||||
key = f"{item.routing_type}_{warning_type}"
|
||||
bussiness_node_id = business_node_ids.get(key, None)
|
||||
if bussiness_node_id:
|
||||
message_template = message_templates.get(key)
|
||||
if message_template and message_template.id:
|
||||
message_queue_ids = self.env["jikimo.message.queue"].sudo().search([
|
||||
("message_template_id", "=", message_template.id),
|
||||
("message_status", "=", "pending"),
|
||||
("res_id", "=", item.id)
|
||||
], limit=1)
|
||||
if not message_queue_ids:
|
||||
overdue_message = '工单已逾期' if item.delivery_warning == 'overdue' else '工单逾期预警'
|
||||
queue_method_name = f'add_queue'
|
||||
@@ -152,8 +174,33 @@ class SFMessageWork(models.Model):
|
||||
args = [f'{item.routing_type}{overdue_message}']
|
||||
# 获取add_queue方法并调用它,传入参数列表
|
||||
getattr(item, queue_method_name)(*args)
|
||||
if item.delivery_warning == 'overdue':
|
||||
# 把消息队列中销售订单预警的状态改为取消发送
|
||||
key = f"{item.routing_type}_{'warning'}"
|
||||
business_node_id_warning = business_node_ids.get(key, None)
|
||||
if business_node_id_warning:
|
||||
message_template_warning = self.env["jikimo.message.template"].search([
|
||||
("model", "=", self._name),
|
||||
("bussiness_node_id", "=", business_node_id_warning)
|
||||
], limit=1)
|
||||
if message_template_warning:
|
||||
work_order_warning = self.env['jikimo.message.queue'].search([
|
||||
('res_id', '=', item.id),
|
||||
('message_status', '=', 'pending'),
|
||||
('message_template_id', '=', message_template_warning.id)
|
||||
])
|
||||
if work_order_warning:
|
||||
logging.info('取消发送:%s' % work_order_warning)
|
||||
work_order_warning.write({'message_status': 'cancel'})
|
||||
|
||||
def _recover_time_warning_func(self):
|
||||
workorder_done = self.env['mrp.workorder'].search([("state", "in", ["done", "rework", "cancel"])])
|
||||
workorder_overdue = workorder_done.filtered(lambda x: x.delivery_warning in ['overdue', 'warning'])
|
||||
workorder_overdue.write({'delivery_warning': 'normal'})
|
||||
if workorder_overdue:
|
||||
workorder_overdue.write({'delivery_warning': 'normal'})
|
||||
message_queue_ids = self.env["jikimo.message.queue"].sudo().search([
|
||||
("message_status", "=", "pending"),
|
||||
("res_id", "in", [item.id for item in workorder_overdue])
|
||||
])
|
||||
if message_queue_ids:
|
||||
message_queue_ids.write({'message_status': 'cancel'})
|
||||
|
||||
@@ -5,24 +5,28 @@ access_jikimo_message_template_group_purchase,jikimo_message_template,jikimo_mes
|
||||
access_jikimo_message_template_group_sf_stock_user,jikimo_message_template,jikimo_message_notify.model_jikimo_message_template,sf_base.group_sf_stock_user,1,1,1,0
|
||||
access_jikimo_message_template_group_sf_order_user,jikimo_message_template,jikimo_message_notify.model_jikimo_message_template,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_jikimo_message_template_group_sf_tool_user,jikimo_message_template,jikimo_message_notify.model_jikimo_message_template,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_jikimo_message_template_group_purchase_director,jikimo_message_template,jikimo_message_notify.model_jikimo_message_template,sf_base.group_purchase_director,1,1,1,0
|
||||
|
||||
access_jikimo_message_bussiness_node_group_sale_salemanager,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_sale_salemanager,1,1,1,0
|
||||
access_jikimo_message_bussiness_node_group_purchase,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_purchase,1,1,1,0
|
||||
access_jikimo_message_bussiness_node_group_sf_stock_user,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_sf_stock_user,1,1,1,0
|
||||
access_jikimo_message_bussiness_node_group_sf_order_user,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_jikimo_message_bussiness_node_group_sf_tool_user,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_jikimo_message_bussiness_node_group_purchase_director,jikimo_message_bussiness_node,jikimo_message_notify.model_jikimo_message_bussiness_node,sf_base.group_purchase_director,1,1,1,0
|
||||
|
||||
access_jikimo_message_queue_group_sale_salemanager,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_sale_salemanager,1,1,1,0
|
||||
access_jikimo_message_queue_group_purchase,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_purchase,1,1,1,0
|
||||
access_jikimo_message_queue_group_sf_stock_user,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_sf_stock_user,1,1,1,0
|
||||
access_jikimo_message_queue_group_sf_order_user,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_jikimo_message_queue_group_sf_tool_user,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_jikimo_message_queue_group_purchase_director,jikimo_message_queue,jikimo_message_notify.model_jikimo_message_queue,sf_base.group_purchase_director,1,1,1,0
|
||||
|
||||
access_jikimo_message_reminder_time_group_sale_salemanager,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_sale_salemanager,1,1,1,0
|
||||
access_jikimo_message_reminder_time_group_purchase,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_purchase,1,1,1,0
|
||||
access_jikimo_message_reminder_time_group_sf_stock_user,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_sf_stock_user,1,1,1,0
|
||||
access_jikimo_message_reminder_time_group_sf_order_user,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_jikimo_message_reminder_time_group_sf_tool_user,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_jikimo_message_reminder_time_group_purchase_director,jikimo_message_reminder_time,jikimo_message_notify.model_jikimo_message_reminder_time,sf_base.group_purchase_director,1,1,1,0
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -30,5 +30,36 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="mrp_workorder_issued_action">
|
||||
<field name="name">工单</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">mrp.workorder</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('mrp.mrp_production_workorder_tree_editable_view')}) ]"/>
|
||||
<!-- (0, 0, {'view_mode': 'kanban', 'view_id': ref('mrp.workcenter_line_kanban')})-->
|
||||
<!-- <field name="target">fullscreen</field>-->
|
||||
<field name="target">current</field>
|
||||
<field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>
|
||||
<field name="context">{'search_default_product': 1, 'search_default_workcenter_id':
|
||||
active_id,'search_default_ready': 1, 'search_default_progress': 1}
|
||||
</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_workorder">
|
||||
没有工单要做!
|
||||
</p>
|
||||
<p>
|
||||
工作订单是作为制造订单的一部分执行的操作。
|
||||
工序在物料清单中定义或直接添加到制造订单中。
|
||||
</p>
|
||||
<p>
|
||||
使用工作台工作中心控制面板直接登记车间中的操作.
|
||||
平板电脑为您的工人提供工作表,并允许他们报废产品,跟踪时间,
|
||||
发起维护请求,执行质量测试等.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -2271,9 +2271,9 @@ class Cutting_tool_standard_library(models.Model):
|
||||
[('code', '=', item['chuck_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||
"handle_id": False if not item['handle_code'] else self.search(
|
||||
[('code', '=', item['handle_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
|
||||
'suitable_machining_methods') else self.env['maintenance.equipment.image']._get_ids(
|
||||
item['suitable_machining_methods']),
|
||||
"suitable_machining_method_ids": [(6, 0, [])] if not item.get('suitable_machining_method')
|
||||
else self.env['maintenance.equipment.image']._get_ids(
|
||||
item['suitable_machining_method']),
|
||||
"blade_tip_characteristics_id": self.env['maintenance.equipment.image'].search(
|
||||
[('name', '=', item['blade_tip_characteristics'])]).id,
|
||||
"handle_type_id": self.env['maintenance.equipment.image'].search(
|
||||
@@ -2304,6 +2304,7 @@ class Cutting_tool_standard_library(models.Model):
|
||||
("active", 'in', [True, False])])
|
||||
cutting_tool_type = self.env['sf.cutting.tool.type'].search(
|
||||
[("code", '=', item['cutting_tool_type_code'])])
|
||||
|
||||
cutting_tool_material = self.env['sf.cutting.tool.material'].search(
|
||||
[("code", '=', item['cutting_tool_material_code'])])
|
||||
materials_model = self.env['sf.materials.model'].search(
|
||||
@@ -3166,5 +3167,5 @@ class MachiningAccuracySync(models.Model):
|
||||
self.env['sf.machining.accuracy'].sudo().create({
|
||||
"sync_id": time['id'],
|
||||
"name": time['name'],
|
||||
"discount": time['discount'],
|
||||
"standard_tolerance": time['standard_tolerance'],
|
||||
})
|
||||
|
||||
@@ -246,26 +246,27 @@ class sf_production_plan(models.Model):
|
||||
record.date_planned_finished = item.date_planned_finished
|
||||
# 计算下一个cnc工单的开始时间
|
||||
last_cnc_start = workorder_list[-1].date_planned_finished + timedelta(minutes=pre_duration)
|
||||
record.state = 'done'
|
||||
# record.production_id.schedule_state = '已排'
|
||||
record.sudo().production_id.schedule_state = '已排'
|
||||
record.sudo().production_id.process_state = '待装夹'
|
||||
# self.env['sale.order'].browse(record.production_id.origin).schedule_status = 'to process'
|
||||
# sale_obj = self.env['sale.order'].search([('name', '=', record.origin)])
|
||||
# if 'S' in sale_obj.name:
|
||||
# sale_obj.schedule_status = 'to process'
|
||||
mrp_production_ids = record.production_id._get_children().ids
|
||||
print('mrp_production_ids', mrp_production_ids)
|
||||
for i in mrp_production_ids:
|
||||
record.env['mrp.production'].sudo().browse(i).schedule_state = '已排'
|
||||
# record.production_id.date_planned_start = record.date_planned_start
|
||||
# record.production_id.date_planned_finished = record.date_planned_finished
|
||||
record.sudo().production_id.production_line_id = record.production_line_id.id
|
||||
if record.production_id.workorder_ids:
|
||||
record.sudo().production_id.workorder_ids.filtered(
|
||||
lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write(
|
||||
{'production_line_id': record.production_line_id.id,
|
||||
'plan_start_processing_time': record.date_planned_start})
|
||||
# 没有工单也能排程
|
||||
record.state = 'done'
|
||||
# record.production_id.schedule_state = '已排'
|
||||
record.sudo().production_id.schedule_state = '已排'
|
||||
record.sudo().production_id.process_state = '待装夹'
|
||||
# self.env['sale.order'].browse(record.production_id.origin).schedule_status = 'to process'
|
||||
# sale_obj = self.env['sale.order'].search([('name', '=', record.origin)])
|
||||
# if 'S' in sale_obj.name:
|
||||
# sale_obj.schedule_status = 'to process'
|
||||
mrp_production_ids = record.production_id._get_children().ids
|
||||
print('mrp_production_ids', mrp_production_ids)
|
||||
for i in mrp_production_ids:
|
||||
record.env['mrp.production'].sudo().browse(i).schedule_state = '已排'
|
||||
# record.production_id.date_planned_start = record.date_planned_start
|
||||
# record.production_id.date_planned_finished = record.date_planned_finished
|
||||
record.sudo().production_id.production_line_id = record.production_line_id.id
|
||||
if record.production_id.workorder_ids:
|
||||
record.sudo().production_id.workorder_ids.filtered(
|
||||
lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write(
|
||||
{'production_line_id': record.production_line_id.id,
|
||||
'plan_start_processing_time': record.date_planned_start})
|
||||
|
||||
# record.date_planned_finished = record.date_planned_start + timedelta(days=3)
|
||||
# record.state = 'done'
|
||||
|
||||
@@ -37,52 +37,4 @@ class Action_Plan_All_Wizard(models.TransientModel):
|
||||
# 判断能否排成
|
||||
self.plan_ids.deal_processing_schedule(self.date_planned_start)
|
||||
self.plan_ids.do_production_schedule()
|
||||
# for plan in temp_plan_ids:
|
||||
# # 处理每个计划
|
||||
# # 比如更新计划状态、分配资源等
|
||||
# # 示例:plan.state = 'scheduled'
|
||||
# print('处理计划:', plan.id)
|
||||
# # 拿到计划对象
|
||||
# plan_obj = self.env['sf.production.plan'].browse(plan.id)
|
||||
# plan_obj.production_line_id = self.production_line_id.id
|
||||
# plan.date_planned_start = self.date_planned_start
|
||||
# plan_obj.do_production_schedule()
|
||||
# plan_obj.state = 'done'
|
||||
_logger.info('处理计划: %s 完成', self.plan_ids.ids)
|
||||
|
||||
# # 获取当前生产线
|
||||
# production_line_id = self.production_line_id
|
||||
# # 获取当前生产线的所有生产订单
|
||||
# production_order_ids = self.env['mrp.production'].search([('production_line_id', '=', production_line_id.id)])
|
||||
# # 获取当前生产线的所有生产订单的id
|
||||
# production_order_id_list = []
|
||||
# for production_order_id in production_order_ids:
|
||||
# production_order_id_list.append(production_order_id.id)
|
||||
# # 获取当前生产线的所有生产订单的排程状态
|
||||
# production_order_plan_state_list = []
|
||||
# for production_order_id in production_order_ids:
|
||||
# production_order_plan_state_list.append(production_order_id.plan_state)
|
||||
# # 如果当前生产线的所有生产订单的排程状态都是已排程,则报错
|
||||
# if all(production_order_plan_state == '已排程' for production_order_plan_state in production_order_plan_state_list):
|
||||
# raise UserError('当前生产线的所有生产订单都已排程,请勿重复排程!')
|
||||
# # 如果当前生产线的所有生产订单的排程状态都是未排程,则报错
|
||||
# if all(production_order_plan_state == '未排程' for production_order_plan_state in production_order_plan_state_list):
|
||||
# raise UserError('当前生产线的所有生产订单都未排程,请先排程!')
|
||||
# # 如果当前生产线的所有生产订单的排程状态都是已完成,则报错
|
||||
# if all(production_order_plan_state == '已完成' for production_order_plan_state in production_order_plan_state_list):
|
||||
# raise UserError('当前生产线的所有生产订单都已完成,请勿重复排程!')
|
||||
# # 如果当前生产线的所有生产订单的排程状态都是已取消,则报错
|
||||
# if all(production_order_plan_state == '已取消' for production_order_plan_state in production_order_plan_state_list):
|
||||
# raise UserError('当前生产线的所有生产订单都已取消,请勿重复排程!')
|
||||
# # 如果当前生产线的所有生产订单的排程状态都是已暂停,则报错
|
||||
# if all(production_order_plan_state == '已暂停' for production_order_plan_state in production_order_plan_state_list):
|
||||
# raise UserError('当前生产线的所有生产订单都已暂停,请勿重复排程!')
|
||||
# # 如果当前生产线的所有生产订单的排程状态都是已完成,则报错
|
||||
# if all(production_order_plan_state == '已完成' for production_order_plan_state in production_order_plan_state_list):
|
||||
# raise UserError('当前生产线的所有生产订单都已完成,请勿重复排程!')
|
||||
# # 如果当前生产线的所有生产订单的排程状态都是已取消,则报错
|
||||
# if all(production_order_plan_state == '已取消' for production_order_plan_state in production_order_plan_state_list):
|
||||
# raise UserError('当前生产线的所有生产订单都已取消,请勿重复排程!')
|
||||
# # 如果当前生产线的所有生产订单的排程状态都是已暂停,则报错
|
||||
# if all(production_order_plan_state == '已暂停' for production_order_plan_state in production_order_plan_state_list):
|
||||
# raise UserError('当前生产线的所有生产订单都已暂停,请勿重复排程!')
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
'author': 'jikimo',
|
||||
'website': 'https://sf.cs.jikimo.com',
|
||||
# 此处依赖sf_manufacturing是因为我要重写其中的一个字段operation_id的string,故需要sf_manufacturing先安装
|
||||
'depends': ['quality_control', 'web_widget_model_viewer', 'sf_manufacturing'],
|
||||
'depends': ['quality_control', 'web_widget_model_viewer', 'sf_manufacturing','jikimo_attachment_viewer'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/view.xml',
|
||||
|
||||
@@ -20,6 +20,12 @@ class QuickEasyOrder(models.Model):
|
||||
_description = '简易下单'
|
||||
_order = 'id desc'
|
||||
|
||||
def _get_machining_precision(self):
|
||||
machinings = self.env['sf.machining.accuracy'].sudo().search([])
|
||||
|
||||
list = [(m.sync_id, m.name) for m in machinings]
|
||||
return list
|
||||
|
||||
name = fields.Char('订单编号', default=lambda self: self.env['ir.sequence'].next_by_code('quick.easy.order'))
|
||||
model_length = fields.Float('长(mm)', digits=(16, 3))
|
||||
model_width = fields.Float('宽(mm)', digits=(16, 3))
|
||||
@@ -27,12 +33,7 @@ class QuickEasyOrder(models.Model):
|
||||
model_volume = fields.Float('体积(mm³)', digits=(16, 3))
|
||||
model_processing_side = fields.Char('加工面', default='A')
|
||||
model_feature = fields.Char('特征')
|
||||
machining_precision = fields.Selection([
|
||||
('0.10', '±0.10mm'),
|
||||
('0.05', '±0.05mm'),
|
||||
('0.03', '±0.03mm'),
|
||||
('0.02', '±0.02mm'),
|
||||
('0.01', '±0.01mm')], string='加工精度', default='0.10')
|
||||
machining_precision = fields.Selection(selection=_get_machining_precision, string='加工精度')
|
||||
material_id = fields.Many2one('sf.production.materials', '材料', tracking=True)
|
||||
material_model_id = fields.Many2one('sf.materials.model', '型号', domain="[('materials_id', '=', material_id)]",
|
||||
tracking=True)
|
||||
@@ -219,7 +220,14 @@ class QuickEasyOrder(models.Model):
|
||||
'total_amount': item.price,
|
||||
'remark': '',
|
||||
'manual_quotation': True,
|
||||
'barcode': barcode
|
||||
'barcode': barcode,
|
||||
'part_number': item.part_drawing_number,
|
||||
'machining_drawings_name': '',
|
||||
'quality_standard_name': '',
|
||||
'machining_drawings_mimetype': '',
|
||||
'quality_standard_mimetype': '',
|
||||
'machining_drawings': item.machining_drawings,
|
||||
'quality_standard': '',
|
||||
})
|
||||
# res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list'])
|
||||
product_id = self.env.ref('sf_dlm.product_template_sf').sudo()
|
||||
|
||||
@@ -55,7 +55,8 @@ class ReSaleOrder(models.Model):
|
||||
store=True, readonly=False, copy=False, precompute=True,
|
||||
states=READONLY_FIELD_STATES, default=fields.Datetime.now)
|
||||
|
||||
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效')
|
||||
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
|
||||
tracking=True)
|
||||
|
||||
# 业务平台分配工厂后在智能工厂先创建销售订单
|
||||
def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address,
|
||||
@@ -117,12 +118,16 @@ class ReSaleOrder(models.Model):
|
||||
|
||||
# 业务平台分配工厂时在创建完产品后再创建销售明细信息
|
||||
def sale_order_create_line(self, product, item):
|
||||
machining_accuracy_name = ''
|
||||
if product.model_machining_precision:
|
||||
machining_accuracy_name = self.env['sf.machining.accuracy'].sudo().search(
|
||||
[('sync_id', '=', product.model_machining_precision)]).name
|
||||
vals = {
|
||||
'order_id': self.id,
|
||||
'product_id': product.id,
|
||||
'name': '%s/%s/%s/%s/±%s/%s' % (
|
||||
'name': '%s/%s/%s/%s/%s/%s' % (
|
||||
product.model_long, product.model_width, product.model_height, product.model_volume,
|
||||
product.model_machining_precision,
|
||||
machining_accuracy_name,
|
||||
product.materials_id.name),
|
||||
'price_unit': product.list_price,
|
||||
'product_uom_qty': item['number'],
|
||||
|
||||
@@ -6,14 +6,20 @@
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<xpath expr="//header/button[@name='action_view_picking']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//header/button[@name='action_rfq_send'][1]" position="before">
|
||||
<button name="button_confirm" type="object" states="sent" string="Confirm Order"
|
||||
context="{'validate_analytic': True}" class="oe_highlight" id="bid_confirm"
|
||||
data-hotkey="v"/>
|
||||
<button name="button_confirm" type="object" states="draft" context="{'validate_analytic': True}"
|
||||
string="Confirm Order" id="draft_confirm"/>
|
||||
<button name="button_cancel" states="draft,to approve,sent,purchase" string="Cancel" type="object" data-hotkey="x" />
|
||||
<button name="action_view_picking"
|
||||
string="接收产品" class="oe_highlight" type="object"
|
||||
attrs="{'invisible': ['|', '|' , ('is_shipped', '=', True), ('state','not in', ('purchase','done')), ('incoming_picking_count', '=', 0)]}"
|
||||
data-hotkey="y" groups="stock.group_stock_user"/>
|
||||
<button name="button_cancel" states="draft,to approve,sent,purchase" string="取消" type="object" data-hotkey="x" />
|
||||
</xpath>
|
||||
<xpath expr="//header/button[@name='button_cancel'][2]" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
|
||||
@@ -80,8 +80,8 @@
|
||||
<field name="unit_price"/>
|
||||
<field name="price" options="{'format': false}"/>
|
||||
<field name="part_drawing_number"/>
|
||||
<!-- <field name="machining_drawings" filename="machining_drawings_name" widget="pdf_viewer"/>-->
|
||||
<!-- <field name="machining_drawings_name" invisible="1"/>-->
|
||||
<field name="machining_drawings" filename="machining_drawings_name" widget="pdf_viewer"/>
|
||||
<field name="machining_drawings_name" invisible="1"/>
|
||||
<field name="sale_order_id"
|
||||
attrs='{"invisible": [("sale_order_id","=",False)],"readonly": [("sale_order_id","!=",False)]}'/>
|
||||
</group>
|
||||
|
||||
@@ -200,6 +200,8 @@ class MrpProduction(models.Model):
|
||||
self[0].write({'is_rework': False})
|
||||
# 修改制造订单 编程状态变为“编程中” 制造订单状态为‘返工’
|
||||
self.write({'programming_state': '编程中', 'work_state': '编程中', 'state': 'rework'})
|
||||
self[0].workorder_ids.filtered(
|
||||
lambda a: a.name == '装夹预调' and a.state not in ['rework', 'done', 'cancel'])._compute_state()
|
||||
if missing_tool_1:
|
||||
logging.info(f'线边、机内缺刀:{missing_tool_1}')
|
||||
# 修改 修改cnc程序的‘刀具状态’ 为 ‘缺刀’
|
||||
|
||||
Reference in New Issue
Block a user