gaoluyang
12 小时以前 e40a608ef9bf51db294d8eefada6a8e2e80cebca
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from pathlib import Path
from zipfile import ZipFile,ZIP_DEFLATED
from lxml import etree as E
import hashlib,json
from copy import deepcopy
root=Path('scripts/quotation-contract-20261015')
source=root/'reference.docx'
target=Path('yudao-module-crm/src/main/resources/templates/contract/sale-contract.docx');target.parent.mkdir(parents=True,exist_ok=True)
ns={'w':'http://schemas.openxmlformats.org/wordprocessingml/2006/main'};W='{'+ns['w']+'}'
with ZipFile(source) as src:
 xml=E.fromstring(src.read('word/document.xml'));body=xml.find('w:body',ns);ps=body.findall('w:p',ns)
 for t in ps[1].findall('.//w:t',ns):
  if '中国科学院西北高原生物研究所' in (t.text or ''):t.text=t.text.replace('中国科学院西北高原生物研究所','${customerName}')
 metadata=ps[4]
 for child in list(metadata):metadata.remove(child)
 ppr=ps[1].find('w:pPr',ns)
 if ppr is not None:metadata.append(deepcopy(ppr))
 run=E.SubElement(metadata,W+'r');rpr=ps[1].find('w:r/w:rPr',ns)
 if rpr is not None:run.append(deepcopy(rpr))
 E.SubElement(run,W+'t').text='合同编号:${contractNo}    合同日期:${contractDate}'
 body.remove(metadata);body.insert(list(body).index(ps[0])+1,metadata)
 for paragraph in ps:
  text=''.join(paragraph.itertext())
  if any(text.startswith(prefix) for prefix in ['第二条','第三条','第四条','第五条','第六条','第七条']):
   prop=paragraph.find('w:pPr',ns)
   if prop is None:prop=E.SubElement(paragraph,W+'pPr')
   keep=prop.find('w:keepNext',ns)
   if keep is None:keep=E.SubElement(prop,W+'keepNext')
   keep.set(W+'val','1')
 table=body.find('w:tbl',ns);rows=table.findall('w:tr',ns)
 for cell,key in zip(rows[1].findall('w:tc',ns),['index','itemName','unitName','count','price','amount']):
  texts=cell.findall('.//w:t',ns);texts[0].text='${'+key+'}'
  for t in texts[1:]:t.text=''
 rowprop=rows[1].find('w:trPr',ns)
 if rowprop is None:rowprop=E.SubElement(rows[1],W+'trPr')
 E.SubElement(rowprop,W+'cantSplit')
 for row in rows[2:4]:table.remove(row)
 for row,text in [(rows[4],'合计金额:${totalPrice}${discountNote}'),(rows[5],'大写金额:${totalUpper}')]:
  texts=row.findall('.//w:t',ns);texts[0].text=text
  for t in texts[1:]:t.text=''
 prop=rows[0].find('w:trPr',ns)
 if prop is None:prop=E.SubElement(rows[0],W+'trPr')
 E.SubElement(prop,W+'tblHeader')
 with ZipFile(target,'w',ZIP_DEFLATED) as dst:
  for info in src.infolist():dst.writestr(info,E.tostring(xml,xml_declaration=True,encoding='UTF-8',standalone=True) if info.filename=='word/document.xml' else src.read(info.filename))
original=Path('D:/WechatRecord/xwechat_files/wxid_vmeut7wztkbp22_1546/temp/RWTemp/2026-10/c40afdcfa98e2b4561823e6babbefa33/虫草购销合同-西高所.doc')
(root/'artifact.md').write_text('''# 合同模板执行说明
原始 DOC 保持不变,使用 Word 转为 reference.docx。版式以该副本为准:保留页面尺寸、字体、段落、原合同全部条款和甲方收款信息。
仅编辑 word/document.xml:乙方名称、标题下的合同编号与日期、产品明细行、合计和大写金额;产品行可按数量克隆,原两条空行移除,表头跨页重复,产品行禁止跨页拆分,条款标题与后文同页。
金额来自合同实际数据,含整单优惠时明确注明优惠金额和实付合计。签章区和签字时间保留为空,不自动代签。
原模板开户行写为公司名称,按原样保留,正式签署前应核对。
'''+f'原始文件 SHA256:{hashlib.sha256(original.read_bytes()).hexdigest()}\nDOCX SHA256:{hashlib.sha256(source.read_bytes()).hexdigest()}\n',encoding='utf-8')
print(target)