Plone技术资料

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1470|回复: 0

湘潭市地方税务局报税系统项目开发总结

[复制链接]
发表于 2019-8-6 16:39:55 | 显示全部楼层 |阅读模式
湘潭市地税局大厅报税系统项目于2017年7月完工验收,至今运行良好。
今天对该项目进行总结,并对在开发过程中运用的技术技巧予以揭示:

一、项目总结
  • 基于Plone5.0.5开发
  • 项目是典型的B/S模式
  • 项目部署:前端Apache/Nginx + 反向代理(Varnish) + 负载均衡(HAProxy) + Plone instance
  • 项目可以跨操作系统平台运行,但推荐用Linux
  • 项目采用dexterity技术设计多级别内容类型
  • 项目采用bootstrap V3作为前台框架
  • 项目大量采用AJAX技术,前端相应迅速,用户体念良好
  • 对纳税数据提供批量导入/导出功能
  • 提供在线优化打印支持
  • 自定义索引,优化搜索查询
  • 底层优化cache技术,支持多用户并行读写访问

二、开发技巧
  • 大量采用"函数式"编程思维,代码级别提升程序性能
    1. # filter contain "u'所有'"
    2.         tag = filter(lambda x: all not in x, tag)
    3. # recover un-category tag (remove:u"未分类-")
    4.         def recovery(value):
    5.             if unclass not in value:return value
    6.             return value.split('-')[1]            
    7.         tag = map(recovery,tag)
    复制代码

  • 大量运用缓存技术,提升并发性能
    1. def _ajax_output_cachekey(method,self,start,size,totalnum,braindata,searchview):
    2.     "ajax table output generator cache key"
    3.     return braindata
    4. ...
    5.     @ram.cache(_ajax_output_cachekey)
    6.     def output(self,start,size,totalnum,braindata,searchview):
    7.         "根据参数total,braindata,返回jason 输出"
    复制代码

  • 大量采用AJAX技术,提升编辑用户体念
    1. $(document).ready(function(){
    2.                 //single click modify checkbox
    3.     $('.checkbox').on('click','.switch-style', function(){
    4.                 var shenbaofou = 'true';
    5.                 var number = $(this).attr('data-num');
    6.                 var checkboxID = $(this).siblings('input');
    7.                 if (checkboxID.is(':checked')) {
    8.                 checkboxID.prop('checked', false);
    9.                 shenbaofou = 'false';        
    10.                 }
    11.                 else {
    12.                 checkboxID.prop('checked', true);
    13.                 $(this).css({"color":"red"});
    14.                 }
    15.                 var action = $(this).attr('data-url');
    16.                 var data = {'shenbaofou':shenbaofou,'number':number};               
    17.                 //located parent object and add css class
    18.                 //$(this).parent().addClass("current");
    19.                 $.post(action,data,function(callback) {
    20.                         if (callback['result']) {
    21.                                 $("#ajax-status-notify div").html(callback['message']);
    22.                                 //$("#ajax-status-notify").show();
    23.                         }                                
    24.                 },'json');
    25.                 return false;        
    26.                 });
    27.                
    28. // modify nashuiren property               
    29.                 $(".p-checkbox").on("click",'.switch-style',function() {
    30.                 var checkboxID = $(this).siblings('input');
    31.                 var shenbaofou = 'true';
    32.                 var property = $(this).attr('data-property');
    33.                 if (checkboxID.is(':checked')) {
    34.                 checkboxID.prop('checked', false);
    35.                 shenbaofou = 'false';        
    36.                 }
    37.                 else {
    38.                 checkboxID.prop('checked', true);
    39.                 $(this).css({"color":"red"});
    40.                 }
    41.                 var action = $("#ajax-target").attr('data-target') + "/@@modify_property";
    42.                 var data = {'shenbaofou':shenbaofou,'property':property};        
    43.                 $.post(action,data,function(callback) {
    44.                         if (callback['result']) {
    45.                                 $("#ajax-status-notify div").html(callback['message']);
    46.                                 //$("#ajax-status-notify").show();
    47.                         }                                
    48.                 },'json');
    49.                 return false;        
    50.                 });
    51. //modify description
    52.                 $(".modifydes").on("click",'.description',function() {
    53.                 $(this).addClass("editing");
    54.                 $(this).parent().parent().addClass("current");
    55.     // display description enter form
    56.     $(".current .ajaxdes").show();
    57.     $(".current .other").hide();
    58.     return false;
    59.     });
    60.     //form ok button
    61.     $(".table").on("click",".current button[name='ok']",function() {               
    62.                 //var id = $(this).attr('data-id');
    63.                 var old = $(".current .editing").html();
    64.                 var description = $(this).parent().find('input').val();
    65.                 if (old == description) {
    66.          $(".current .ajaxdes").hide();
    67.          $(".current .other").show();
    68.                 $(".current .editing").removeClass("editing");
    69.                 $(".current").removeClass("current");               
    70.                     return false;
    71.                 }               
    72.                 var id = $(".current .editing").attr('data-id');
    73.                 var action = $("#ajax-target").attr('data-target') + "/@@modify_description";
    74.                 var data = {'description':description,'subobj_id':id};        
    75.                 $.post(action,data,function(callback) {
    76.                         if (callback['result']) {
    77.                         $(".current .editing").html(description);
    78.                  $(".current .ajaxdes").hide();
    79.                  $(".current .other").show();
    80.                 $(".current .editing").removeClass("editing");
    81.                 $(".current").removeClass("current");               
    82.                         $("#ajax-status-notify div").html(callback['message']);
    83.                         //$("#ajax-status-notify").show();
    84.                         }                                
    85.                 },'json');
    86.                 return false;        
    87.                 });
    88.                 //form cancel button
    89.     $(".table").on("click",".current button[name='cancel']",function() {
    90.          $(".current .ajaxdes").hide();
    91.          $(".current .other").show();
    92.          $(".current .editing").removeClass("editing");
    93.          $(".current").removeClass("current");
    94.                 return false;                        
    95.                 });                                                
    96. // modify number
    97.                 $(".number-row").on('click','.number',function() {
    98.                 $(this).addClass("focus");
    99.                 $(this).parent().parent().parent().addClass("running");
    100.     // display number enter form
    101.     $(".running .form").show();
    102.     $(".running .number-row").hide();
    103.     return false;
    104.     });
    105.     $(".bottom").on("click",".running button[name='ok']",function() {
    106.             var old = $(".running .focus").html();
    107.             var number = $(".running .focus").attr('data-num');
    108.                 var action = $(".running .focus").attr('data-url') + "/@@modify_ancijilu";
    109.                 var shenbaocishu = $(this).parent().find('input').val();
    110.                 if (old == shenbaocishu) {
    111.          $(".running .form").hide();
    112.          $(".running .number-row").show();
    113.                 $(".running .focus").removeClass("focus");
    114.                 $(".running").removeClass("running");               
    115.                     return false;
    116.                 }
    117.                 var data = {'shenbaocishu':shenbaocishu,'number':number};
    118.                 $.post(action,data,function(callback) {
    119.                         if (callback['result']) {
    120.                           $(".running .focus").html(shenbaocishu);
    121.                           $(".running .focus").css({"color":"red"});
    122.          $(".running .form").hide();
    123.          $(".running .number-row").show();
    124.                 $(".running .focus").removeClass("focus");
    125.                 $(".running").removeClass("running");               
    126.                         $("#ajax-status-notify div").html(callback['message']);
    127.                         //$("#ajax-status-notify").show();
    128.                         }                                
    129.                 },'json');
    130.                 return false;        
    131.                 });        
    132.     $(".bottom").on("click",".running button[name='cancel']",function() {
    133.          $(".running .form").hide();
    134.          $(".running .number-row").show();
    135.                 $(".running .focus").removeClass("focus");
    136.                 $(".running").removeClass("running");
    137.                 return false;                        
    138.                 });   
    139.     //select batch modify               
    140.         $(".outer").on("click",".selectall",function() {
    141.                 var url = $("#ajax-target").attr('data-target') + "/@@batch_modify";
    142.                 var number = $(this).attr('data-num');
    143.                 var actionid = $(this).siblings('.data').attr('data-id');
    144.                 $(this).find('input').prop('checked', true);               
    145.                 $(this).siblings('.data').find('input').prop('checked', true);
    146.                 $(this).siblings('.data').find('span').css({"color":"red"});
    147.         var action = "selectall";
    148.                 var data = {'objid':actionid,'action':action,'number':number};
    149.                 $(this).addClass('unselectall').removeClass('selectall');
    150.                 $.post(url,data,function(callback) {
    151.                         if (callback['result']) {
    152.                                 $("#ajax-status-notify div").html(callback['message']);
    153.                                 //$("#ajax-status-notify").show();
    154.                         }                                
    155.                 },'json');
    156.                 return false;
    157.         });

    158.         $(".outer").on("click",".unselectall",function() {
    159.                 var url = $("#ajax-target").attr('data-target') + "/@@batch_modify";
    160.                 var number = $(this).attr('data-num');
    161.                 var actionid = $(this).siblings('.data').attr('data-id');
    162.                 $(this).find('input').prop('checked', false);
    163.                 $(this).siblings('.data').find('input').prop('checked', false);
    164.         var action = "unselectall";
    165.                 var data = {'objid':actionid,'action':action,'number':number};
    166.                 $(this).addClass('selectall').removeClass('unselectall');
    167.                 $.post(url,data,function(callback) {
    168.                         if (callback['result']) {
    169.                                 $("#ajax-status-notify div").html(callback['message']);
    170.                                 //$("#ajax-status-notify").show();
    171.                         }                                
    172.                 },'json');
    173.                 return false;
    174.         });                        
    175. }
    176. );
    复制代码

  • 自定义索引,敲入4个键,即提示查询结果,提升搜粟查询体念,显著提升工作效率
    1. @indexer(Inashuiren)
    2. def nashuiren_searchable_text_indexer(obj):
    3.     """Dynamic searchable text indexer.任意敲入纳税人市别号中4位字母
    4.     ,即返回相关查询结果
    5.     """
    6.     title = obj.title
    7.     shibiehao = obj.guanlidaima.strip()
    8.     ln = len(shibiehao)
    9.     size = 4
    10.     batch = ln // size
    11.     indexed = []
    12.     indexed.append(shibiehao)   
    13.     for i in range(batch):
    14.         new = shibiehao[size * i:]        
    15.         indexed.append(new)      
    16.     batch = (ln-1) //size
    17.     shibiehao = shibiehao[1:]
    18.     for i in range(batch):
    19.         new = shibiehao[size * i:]
    20.         indexed.append(new)
    21.     batch = (ln-2) //size
    22.     shibiehao = shibiehao[2:]
    23.     for i in range(batch):
    24.         new = shibiehao[size * i:]
    25.         indexed.append(new)
    26.     batch = (ln-3) //size
    27.     shibiehao = shibiehao[3:]
    28.     for i in range(batch):
    29.         new = shibiehao[size * i:]
    30.         indexed.append(new)                       
    31.     indexed.append(title)
    32. #     indexed.append(shibiehao)
    33.     return ' '.join(map(encode_utf8,indexed))
    复制代码

  • 自定义livesearch功能,(baoshui,policy,theme三个包配合),主要代码在policy包如下:
    1.    <browser:page
    2.       name="nashuiren-ajax-search"
    3.       class=".livesearch.NashuirenAjaxSearch"
    4.       permission="zope2.View"
    5.       for="plone.app.layout.navigation.interfaces.INavigationRoot"
    6.       />

    7. # -*- coding: utf-8 -*-
    8. from shuiwu.baoshui.content.nashuiku import Inashuiku
    9. from shuiwu.baoshui.content.nashuiren import Inashuiren
    10. from Products.CMFPlone.browser.search import MULTISPACE,BAD_CHARS,quote_chars
    11. from Products.CMFPlone.browser.search import AjaxSearch
    12. from DateTime import DateTime
    13. from Products.CMFCore.utils import getToolByName
    14. from Products.CMFPlone.PloneBatch import Batch
    15. from Products.CMFPlone.browser.navtree import getNavigationRoot
    16. from Products.ZCTextIndex.ParseTree import ParseError
    17. from ZTUtils import make_query
    18. from plone.app.contentlisting.interfaces import IContentListing
    19. from plone.registry.interfaces import IRegistry
    20. from zope.component import getMultiAdapter
    21. from zope.component import queryUtility
    22. from zope.component import getUtility
    23. from zope.i18nmessageid import MessageFactory
    24. from zope.publisher.browser import BrowserView

    25. import json

    26. _ = MessageFactory('plone')


    27. class NashuirenAjaxSearch(AjaxSearch):
    28.    
    29.     def getPathQuery(self):
    30.         """返回 纳税人库目录查询条件
    31.         """
    32.         query = {'path':self.getDBFolder()}               
    33.         return query         
    34.         
    35. # roll table output
    36.     def getDBFolder(self):
    37.         
    38.         catalog = getToolByName(self.context, 'portal_catalog')
    39.         brains = catalog({'object_provides':Inashuiku.__identifier__})
    40.         path = brains[0].getPath()
    41.         return path
    42.    
    43.     def filter_query(self, query):
    44.         request = self.request
    45.         text = query.get('SearchableText', None)
    46.         if text is None:
    47.             text = request.form.get('SearchableText', '')
    48.         if not text:
    49.             # Without text, must provide a meaningful non-empty search
    50.             return

    51.         #nashuiren_searchable_query = {}
    52.         nquery = self.getPathQuery()
    53.         if text:
    54. #             nquery['SearchableText'] = self.munge_search_term(text)
    55.             nquery['fulltext'] = self.munge_search_term(text)
    56.         nquery['object_provides'] = Inashuiren.__identifier__
    57.         return nquery
    复制代码

  • 大量更新脚步程序,(程序多个版本升级,但须保障数据绝不丢失!)
    1.    <genericsetup:importStep
    2.         name="shuiwu.policy-postInstall"
    3.         title="shuiwu.policy post_install import step"
    4.         description="Post install import step from shuiwu.policy"
    5.         handler=".setuphandlers.post_install">
    6.         <depends name='typeinfo' />
    7.     </genericsetup:importStep>
    8.   <genericsetup:upgradeStep
    9.       title="Add sub tree for nashuiren"
    10.       description="update step to add sub tree for nashuiren."
    11.       source="1002"
    12.       destination="1003"
    13.       handler="shuiwu.policy.migration.createChildTree"
    14.       profile="shuiwu.baoshui:default"/>      
    15.   <genericsetup:upgradeStep
    16.       title="Add niandu container to nashuiren"
    17.       description="update step to add niandu container to nashuiren."
    18.       source="1003"
    19.       destination="1004"
    20.       handler="shuiwu.policy.migration.appendNianduContainer"
    21.       profile="shuiwu.baoshui:default"/>
    22.       
    23.   <genericsetup:upgradeStep
    24.       title="Add niandu container to nashuiren2"
    25.       description="update step to add niandu container to nashuiren2."
    26.       source="1003"
    27.       destination="1004"
    28.       handler="shuiwu.policy.migration.appendNianduContainer2"
    29.       profile="shuiwu.baoshui:default"/>      

    30.   <genericsetup:upgradeStep
    31.       title="rebuild nashuiren index"
    32.       description="update step for rebuild nashuiren index."
    33.       source="1003"
    34.       destination="1004"
    35.       handler="shuiwu.policy.migration.build_index_nashuiren"
    36.       profile="shuiwu.baoshui:default"/>
    37.   <genericsetup:upgradeStep
    38.       title="init subject for nashuiren"
    39.       description="init subject for nashuiren."
    40.       source="1003"
    41.       destination="1004"
    42.       handler="shuiwu.policy.migration.init_subjectfornashuiren"
    43.       profile="shuiwu.baoshui:default"/>      
    44.   <genericsetup:upgradeStep
    45.       title="migrate subject"
    46.       description="migrate subject to niandu."
    47.       source="1003"
    48.       destination="1004"
    49.       handler="shuiwu.policy.migration.migratesubject2niandu"
    50.       profile="shuiwu.baoshui:default"/>

    51.   <genericsetup:upgradeStep
    52.       title="geti nashuiren set default view"
    53.       description="geti nashuiren set default view."
    54.       source="1003"
    55.       destination="1004"
    56.       handler="shuiwu.policy.migration.nashuiren_set_defaultview"
    57.       profile="shuiwu.baoshui:default"/>
    58.   <genericsetup:upgradeStep
    59.       title="remove duplicated Nashuiren"
    60.       description="remove duplicated Nashuiren"
    61.       source="1003"
    62.       destination="1004"
    63.       handler="shuiwu.policy.migration.nashuiren_remove_duplicate"
    64.       profile="shuiwu.baoshui:default"/>  
    复制代码
    1. # -*- coding: utf-8 -*-
    2. from plone import api
    3. from Products.CMFCore.utils import getToolByName
    4. import datetime
    5. from shuiwu.baoshui.content.nashuiren import Inashuiren
    6. from shuiwu.baoshui.content.niandu import Iniandu
    7. from shuiwu.baoshui.subscriber import subids
    8. from shuiwu.baoshui.subscriber import getout,tagroup,yuedu_subjects,jidu_subjects,ling_subjects

    9. ## start 删除重复纳税人(title相同,id不同)
    10. id = set()
    11. def nashuiren_remove_duplicate(context):
    12.     pc = getToolByName(context, "portal_catalog")
    13.     query = {"object_provides":Inashuiren.__identifier__,"sort_on":"created","sort_order":"reverse"}
    14.     bns = pc(query)
    15.     bns = filter(nashuiren_is_repeat,bns)
    16.     finished = map(delete_obj,bns)
    17. def nashuiren_is_repeat(brain):
    18.     "brain is nashuiren brain"
    19.     catalog = api.portal.get_tool(name='portal_catalog')
    20.     title = brain.Title

    21.     id.add(brain.id)
    22.     newbns = catalog({"object_provides":Inashuiren.__identifier__,"sort_on":"created","sort_order":"forward"})
    23.     result = False
    24.     for bn in newbns:        
    25.         if bn.Title ==  title and bn.id not in id:
    26.             result = True
    27.             id.add(bn.id)
    28.             break            
    29.         else:
    30.             continue
    31.     return result
    32.    
    33. def delete_obj(brain):
    34.     obj = brain.getObject()
    35.     portal = api.portal.get()
    36.     api.content.delete(obj=obj)
    37. ## end 删除重复纳税人(title相同,id不同)

    38. ## start 內资个体设置默认视图
    39. def nashuiren_set_defaultview(context):
    40.     pc = getToolByName(context, "portal_catalog")
    41.     query = {"object_provides":Inashuiren.__identifier__}
    42.     bns = pc(query)
    43.     bns = filter(nashuiren_is_geti,bns)
    44.     finished = map(setlayout,bns)
    45. def nashuiren_is_geti(brain):
    46.     "brain is nashuiren brain"
    47.     if brain.regtype ==  getout[0].encode('utf-8'):
    48.         return True
    49.     else:
    50.         return False

    51. def setlayout(brain):
    52.     obj = brain.getObject()
    53.     obj.setLayout("view")
    54. ## end 內资个体设置默认视图
    55. def findid_noteq_guanlidaima(context):
    56.     pc = getToolByName(context, "portal_catalog")
    57.     query = {"object_provides":Inashuiren.__identifier__}
    58.     bns = pc(query)
    59.     bns = [bn.id for bn in bns if bns.id != bns.guanlidaima]   

    60. def build_index_nashuiren(context):
    61.     "for nashuiren rebuild indexs"
    62.     #search all nashuiren objects that have not sub object
    63.     pc = getToolByName(context, "portal_catalog")
    64.     query = {"object_provides":Inashuiren.__identifier__}
    65.     bns = pc(query)
    66.     finished = map(rebuild_index,bns)

    67. ##start迁移年度记录下面的子对象到纳税人对象(父对象)
    68. def migrateback2nashuiren(context):
    69.     "for nashuiren rebuild indexs"
    70.     #search all nashuiren objects that have not sub object
    71.     pc = getToolByName(context, "portal_catalog")
    72.     query = {"object_provides":Iniandu.__identifier__}
    73.     bns = pc(query)
    74.     finished = map(rebuild_index,bns)

    75. ##end 迁移年度记录下面的子对象到纳税人对象(父对象)
    76. ## start update empty subject to init subject for nashuiren
    77. def init_subjectfornashuiren(context):
    78.     pc = getToolByName(context, "portal_catalog")
    79.     query = {"object_provides":Inashuiren.__identifier__}
    80. #     query["Subject"] = tuple()
    81.     bns = pc(query)
    82.     bns = filter(nashuiren_is_empty_subject,bns)
    83. #     import pdb
    84. #     pdb.set_trace()
    85.     finished = map(init_subject,bns)
    86. def nashuiren_is_empty_subject(brain):
    87.     "brain is nashuiren brain"
    88.     if brain.regtype ==  getout[0].encode('utf-8'):return False
    89.     if len(brain.Subject) < 1:
    90.         return True
    91.     else:
    92.         return False
    93. def init_subject(brain):
    94.     "migrate brain's subject to sub-niandu object"
    95.     obj = brain.getObject()
    96.     status = obj.status
    97.     description = obj.description
    98.     shuiguanyuan = obj.shuiguanyuan
    99.     init_tags = []
    100.     if status != "":
    101.         group = tagroup[0].encode("utf-8")
    102.         tag = "%s-%s" %(group,status)
    103.         init_tags.append(tag)
    104.     if description != "":
    105.         group = tagroup[1].encode("utf-8")
    106.         tag = "%s-%s" %(group,description)
    107.         init_tags.append(tag)
    108.     if shuiguanyuan != "":
    109.         group = tagroup[2].encode("utf-8")
    110.         tag = "%s-%s" %(group,shuiguanyuan)
    111.         init_tags.append(tag)
    112.     subjects = yuedu_subjects + jidu_subjects + ling_subjects + init_tags   
    113.     obj.setSubject(tuple(subjects))                        
    114.     obj.reindexObject(idxs=["Subject"])
    115. ## end update empty subject to init subject for nashuiren   
    116. def migratesubject2niandu(context):
    117.     pc = getToolByName(context, "portal_catalog")
    118.     query = {"object_provides":Inashuiren.__identifier__}
    119.     bns = pc(query)
    120.     bns = filter(niandu_is_empty_subject,bns)
    121.     finished = map(migrate_subject,bns)   
    122.         
    123. def niandu_is_empty_subject(brain):
    124.     "brain is nashuiren brain"
    125.     if len(brain.Subject) > 1:
    126.         return True
    127.     else:
    128.         return False
    129.    
    130. def migrate_subject(brain):
    131.     "migrate brain's subject to sub-niandu object"
    132.     subjects = brain.Subject
    133.     nashuiren = brain.getObject()
    134.     son = nashuiren['2016']
    135.     son.setSubject(tuple(subjects))
    136.     nashuiren.setSubject(tuple())                        
    137.     son.reindexObject(idxs=["Subject"])   

    138. def rebuild_index(brain):
    139.     obj = brain.getObject()
    140.     obj.reindexObject(idxs=["Subject","Title","Description","status","regtype","shuiguanyuan",
    141.                             "caiwufuzeren","caiwufuzerendianhua","banshuiren","banshuirendianhua",
    142.                             "guanlidaima","dengjiriqi"])      

    143. def createChildTree(context):
    144.     "for nashuiren create sub-child-tree"
    145.     #search all nashuiren objects that have not sub object
    146.     pc = getToolByName(context, "portal_catalog")
    147.     query = {"object_provides":Inashuiren.__identifier__}
    148.     bns = pc(query)
    149.     bns = filter(everypathsearchFilter,bns)
    150.     if len(bns) > 2000:
    151.         bns = bns[:1999]     
    152. #     bns = map(map_build_subtree,gen_everypathsearchFilter(bns))   
    153.     finishlist = map(map_build_subtree,bns)
    154.         
    155. def getTargetobj(context,objid):
    156.     "get target nashuiren object that has been created sub tree by object id"
    157.     pc = getToolByName(context, "portal_catalog")
    158.     query = {"object_provides":Inashuiren.__identifier__,'id':objid}
    159.     bns = pc(query)
    160.     return bns[0].getObject()
    161.       
    162. def map_build_subtree(brain):
    163.     "create new niandu subtree"
    164.     obj = brain.getObject()
    165.     id = '2017'
    166.     target = api.content.create(
    167. #     id = datetime.datetime.today().strftime("%Y"),
    168.     id = id,
    169.     type='shuiwu.baoshui.niandu',
    170.     title=u'%s年度记录' % id,
    171.     container=obj)
    172.     status = obj.status
    173.     description = obj.description
    174.     shuiguanyuan = obj.shuiguanyuan
    175.     init_tags = []
    176.     if status != "":
    177.         group = tagroup[0].encode("utf-8")
    178.         tag = "%s-%s" %(group,status)
    179.         init_tags.append(tag)
    180.     if description != "":
    181.         group = tagroup[1].encode("utf-8")
    182.         tag = "%s-%s" %(group,description)
    183.         init_tags.append(tag)
    184.     if shuiguanyuan != "":
    185.         group = tagroup[2].encode("utf-8")
    186.         tag = "%s-%s" %(group,shuiguanyuan)
    187.         init_tags.append(tag)
    188.     subjects = yuedu_subjects + jidu_subjects + ling_subjects + init_tags   
    189.     target.setSubject(tuple(subjects))                        
    190.     target.reindexObject(idxs=["Subject"])
    191.    # Put the tasks into the queue as a tuple
    192.     for subid,title in subids:
    193.         title = title.encode('utf-8')
    194.         type="shuiwu.baoshui.%s" % subid
    195.         directory = api.content.create(type=type,id=subid,title=title,container=target)   

    196. def pathsearchFilter(brain):
    197.     "search the specify brain, path of the brain,if the path has sub-object,return True"
    198.     context = brain.getObject()
    199.     pc = getToolByName(context, "portal_catalog")
    200.     query = {"path":"/".join(context.getPhysicalPath())}
    201.     bns = pc(query)
    202.     if len(bns) <= 1:
    203.         return True
    204.     else:
    205.         return False
    206. def gen_everypathsearchFilter(brains):
    207.     "search the specify brain, path of the brain,if the path has sub-object,return True"
    208.     for brain in brains:
    209.         context = brain.getObject()
    210.         pc = getToolByName(context, "portal_catalog")
    211.         query = {"path":"/".join(context.getPhysicalPath())}
    212.         #     id = datetime.datetime.today().strftime("%Y")
    213.         query['id'] = '2017'
    214.         bns = pc(query)
    215.         if len(bns) < 1:
    216.             yield context
    217.         else:
    218.             continue

    219. def everypathsearchFilter(brain):
    220.     "search the specify brain, path of the brain,if the path has sub-object,return True"
    221.     if brain.regtype ==  getout[0].encode('utf-8'):return False
    222.     context = brain.getObject()
    223.     pc = getToolByName(context, "portal_catalog")
    224.     query = {"path":"/".join(context.getPhysicalPath())}
    225. #     id = datetime.datetime.today().strftime("%Y")
    226.     query['id'] = '2017'
    227.     bns = pc(query)
    228.     if len(bns) < 1:
    229.         return True
    230.     else:
    231.         return False   
    232. def notexistsearchFilter(brain):
    233.     "if not exist niandu object,return True,else return False"
    234.     context = brain.getObject()
    235.     pc = getToolByName(context, "portal_catalog")
    236.     query = {"object_provides":Iniandu.__identifier__}
    237. #     query['object_provides'] = Iniandu.__identifier__
    238.     query["path"] = "/".join(context.getPhysicalPath())
    239.     bns = pc(query)
    240.     if len(bns) < 1:
    241.         return True
    242.     else:
    243.         return False
    244.    
    245. def notmoveFilter(brain):
    246.     "if not exist niandu object,return True,else return False"
    247.     if brain.regtype ==  getout[0].encode('utf-8'):return False
    248.     context = brain.getObject()
    249.     bns = api.content.find(context=context,depth=1)
    250.     if len(bns) > 1:
    251.         return True
    252.     else:
    253.         return False


    254. ## start migrate subobj to niandu            
    255. def appendNianduContainer(context):
    256.     "niandu object append to nashuiren container"
    257.     pc = getToolByName(context, "portal_catalog")
    258.     query = {"object_provides":Inashuiren.__identifier__}
    259.     bns = pc(query)
    260.     bns = filter(notmoveFilter,bns)
    261.     if len(bns) > 1400:
    262.         bns = bns[:699]
    263.     bns = map(mapc,bns)
    264. #     bngenerator = generator_notmoveFilter(bns)   
    265. #     import pdb
    266. #     pdb.set_trace()  
    267. #     for gen in bngenerator:
    268. #         map4obj(gen)

    269. def appendNianduContainer2(context):
    270.     "niandu object append to nashuiren container"
    271.     pc = getToolByName(context, "portal_catalog")
    272.     query = {"object_provides":Inashuiren.__identifier__}
    273.     bns = pc(query)
    274.     bns = filter(notmoveFilter,bns)
    275.     if len(bns) > 1200:
    276.         bns = bns[700:]
    277. #     bns = map(mapc,filter(notmoveFilter,bns))
    278.     bngenerator = generator_notmoveFilter(bns)   
    279. #     import pdb
    280. #     pdb.set_trace()  
    281.     for gen in bngenerator:
    282.         map4obj(gen)
    283.                      
    284. def generator_notmoveFilter(brains):
    285.     "if not exist niandu object,return True,else return False"
    286.     for brain in brains:
    287.         context = brain.getObject()
    288.         bns = api.content.find(context=context,depth=1)
    289.         if len(bns) > 1:
    290.             yield context
    291.         else:
    292.             continue
    293. def map4obj(obj):
    294.     "new create niandu container and move nashuiren's children to it"   
    295. #     id = datetime.datetime.today().strftime("%Y")
    296.     id = '2016'
    297.     try:
    298.         target = obj[id]
    299.     except:        
    300.         target = api.content.create(
    301.                                     id = id,
    302.                                     type='shuiwu.baoshui.niandu',
    303.                                     title=u'年度记录',
    304.                                     container=obj)         
    305.    
    306.     subbrains = api.content.find(context=obj,depth=1)
    307.     subgenerator = subobj_generator(subbrains,id)
    308. #     import pdb
    309. #     pdb.set_trace()
    310.     for subobj in subgenerator:
    311.         api.content.move(source=subobj, target=target)
    312. def subobj_generator(brains,id):
    313.     for bn in brains:
    314.         if bn.id == id: continue
    315.         yield bn.getObject()      
    316.    
    317. ## end migrate subobj to niandu container


    318. def mapc(brain):
    319.     "new create niandu container and move nashuiren's children to it"

    320.     obj = brain.getObject()
    321. #     id = datetime.datetime.today().strftime("%Y")
    322.     id = '2016'   
    323. #     target = api.content.create(
    324. #     id = id
    325. #     type='shuiwu.baoshui.niandu',
    326. #     title=u'年度记录',
    327. #     container=target)
    328.          
    329.     target = obj[id]   
    330.     subbrains = api.content.find(context=obj,depth=1)

    331.     for subbrain in subbrains:
    332.         if subbrain.id == id: continue
    333.         subobj = subbrain.getObject()
    334.         api.content.move(source=subobj, target=target)        

    335. # reset guishu keshi
    336. model = u'湖南省湘潭高新技术产业开发区地方税务局'.encode('utf-8')

    337. def resetDescription(context):
    338.     "湖南省湘潭高新技术产业开发区地方税务局税源管理三科 change to 税源管理三科"
    339.    
    340.     pc = getToolByName(context, "portal_catalog")
    341.     query = {"object_provides":Inashuiren.__identifier__}
    342.     bns = pc(query)
    343. #     import pdb
    344. #     pdb.set_trace()
    345.     bns = filter(zipFilter,bns)
    346. #     if len(bns) > 5:
    347. #         bns = bns[:4]   
    348.     finishlist = map(mapf,bns)      
    349.         
    350. def zipFilter(brain):
    351.     "if description field  exist '湖南省湘潭高新技术产业开发区地方税务局' ,return True,else return False"
    352.     des = brain.Description
    353.     if isinstance(des, unicode):
    354.         des = des.encode('utf-8')
    355.     if model in des:
    356.         return True
    357.     else:
    358.         return False        

    359. def mapf(brain):
    360.     "replace"

    361.     target = brain.getObject()
    362.     des = target.description
    363.     if isinstance(des, unicode):
    364.         des = des.encode('utf-8')
    365.     newd = des.replace(model,'')
    366.     target.description = newd
    367.     target.reindexObject(idxs=['description'])
    368.   
    369. # reset title for niandu
    370. modelid = "%s" % id
    371. def resetTitle(context):
    372.     "湖南省湘潭高新技术产业开发区地方税务局税源管理三科 change to 税源管理三科"
    373.    
    374.     pc = getToolByName(context, "portal_catalog")
    375.     query = {"object_provides":Iniandu.__identifier__}
    376.     bns = pc(query)

    377.     bns = filter(idFilter,bns)
    378. #     if len(bns) > 5:
    379. #         bns = bns[:4]   
    380.     finishlist = map(maptitle,bns)      
    381.         
    382. def idFilter(brain):
    383.     "if title field  exist '<built-in function id>' ,return True,else return False"
    384.     des = brain.Title
    385.     if isinstance(des, unicode):
    386.         des = des.encode('utf-8')
    387.     if modelid in des:
    388.         return True
    389.     else:
    390.         return False        

    391. def maptitle(brain):
    392.     "replace"

    393.     target = brain.getObject()
    394.     des = target.title
    395.     if isinstance(des, unicode):
    396.         des = des.encode('utf-8')
    397.     newd = des.replace(modelid,'')
    398.     target.description = newd
    399.     target.reindexObject(idxs=['Title'])   
    400.    


    复制代码

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|Plone技术资料 ( 湘ICP备14006519号-1 )

GMT+8, 2019-10-22 08:59 , Processed in 0.046441 second(s), 14 queries , Gzip On.

Powered by Plone! X3.4

© 2001-2019 Plone.org.

快速回复 返回顶部 返回列表