def test_removes_simple_field_but_keeps_value(self): document = Document( docx_path('outdated_docproperty_with_umlauts.docx')) assert len( document.paragraphs) == 1, 'input file should contain 1 paragraph' fields = xpath(document.element.body, simple_field_expression(u"F\xfc\xfc")) assert len(fields) == 1, 'should contain one simple field docproperty' assert document.paragraphs[0].text == u'Hie chund ds property: ' assert fields[0].text == u'xxx' CustomProperties(document).dissolve_fields(u"F\xfc\xfc") fields = xpath(document.element.body, simple_field_expression(u"F\xfc\xfc")) assert len(fields) == 0, 'should not contain any docproperties anymore' # when simple field is removed, the value is moved one up in the hierarchy assert document.paragraphs[0].text == u'Hie chund ds property: xxx'
def test_doc_properties_are_not_created_when_disabled(self, browser): self.login(self.regular_user, browser) with freeze(datetime(2020, 10, 28, 0, 0)): browser.open(self.dossier, view='document_with_template') browser.fill({ 'form.widgets.template': str(getUtility(IIntIds).getId(self.asset_template)), 'Title': 'Test Docx', }).save() document = self.dossier.listFolderContents()[-1] self.assertEquals(u'Test Docx.docx', document.file.filename) with TemporaryDocFile(document.file) as tmpfile: properties = CustomProperties(Document(tmpfile.path)).items() self.assertItemsEqual([], properties)
def test_get_doc_properties(): document = Document(docx_path('docproperties.docx')) props = CustomProperties(document) assert props['Text Property'] == 'Foo Bar' assert props['Number Property'] == 123 assert props['Boolean Property'] is True assert props['Date Property'] == datetime(2019, 6, 11, 10, 0) assert props.get('Text Property') == 'Foo Bar' assert props.get('Number Property') == 123 assert props.get('Boolean Property') is True assert props.get('Date Property') == datetime(2019, 6, 11, 10, 0)
def test_complex_docprop_fields_with_multiple_textnodes_are_updated(self): document = Document(docx_path('spellchecked_docproperty.docx')) paragraphs = xpath(document.element.body, '//w:p') assert len(paragraphs) == 1, 'input file contains one paragraph' assert len(xpath(document.element.body, '//w:instrText')) == 1, \ 'input contains one complex field docproperty' w_p = paragraphs[0] cached_values = cached_complex_field_values(w_p) assert len(cached_values) == 4, \ 'doc property value is scattered over 4 parts' assert ''.join(cached_values) == 'i will be spllchecked!' CustomProperties(document).update_all() w_p = xpath(document.element.body, '//w:p')[0] cached_values = cached_complex_field_values(w_p) assert len(cached_values) == 1, \ 'doc property value has been reset to one cached value' assert cached_values[0] == 'i will be spllchecked!'
def test_complex_docprop_with_multiple_textnode_in_same_run_are_updated(self): document = Document(docx_path('two_textnodes_in_run_docproperty.docx')) paragraphs = xpath(document.element.body, '//w:p') assert 1 == len(paragraphs), 'input file contains one paragraph' assert 1 == len(xpath(document.element.body, '//w:instrText')), \ 'input contains one complex field docproperty' w_p = paragraphs[0] cached_values = cached_complex_field_values(w_p) assert 2 == len(cached_values), \ 'doc property value is scattered over 2 parts' assert 'Hello there' == ''.join(cached_values) CustomProperties(document).update_all() w_p = xpath(document.element.body, '//w:p')[0] cached_values = cached_complex_field_values(w_p) assert 1 == len(cached_values), \ 'doc property value has been reset to one cached value' assert 'i will be spllchecked!' == cached_values[0]
def test_complex_docprop_fields_with_multiple_textnodes_are_updated(): document = Document(docx_path('spellchecked_docproperty.docx')) paragraphs = xpath(document.element.body, '//w:p') assert 1 == len(paragraphs), 'input file contains one paragraph' assert 1 == len(xpath(document.element.body, '//w:instrText')), \ 'input contains one complex field docproperty' w_p = paragraphs[0] cached_value = xpath(w_p, XPATH_CACHED_DOCPROPERTY_VALUES) assert 4 == len(cached_value), \ 'doc property value is scattered over 4 parts' assert 'i will be spllchecked!' == ''.join( each.text for each in cached_value) CustomProperties(document).update_all() w_p = xpath(document.element.body, '//w:p')[0] cached_value = xpath(w_p, XPATH_CACHED_DOCPROPERTY_VALUES) assert 1 == len(cached_value), \ 'doc property value has been reset to one cached value' assert 'i will be spllchecked!' == cached_value[0].text
def test_updates_docproperties_shared_header_footer(self): document = Document( docx_path('docproperties_shared_header_footer_2_sections.docx')) # the same header should be referenced by both sections # the sections should be considered as linked header_1 = document.sections[0].header header_2 = document.sections[1].header assert not header_1.is_linked_to_previous assert header_2.is_linked_to_previous assert_complex_field_value(u'blub', header_1.part.element, u'shared.header') assert_complex_field_value(u'blub', header_2.part.element, u'shared.header') # the same footer should be referenced by both sections # the sections should be considered as linked footer_1 = document.sections[0].footer footer_2 = document.sections[1].footer assert not footer_1.is_linked_to_previous assert footer_2.is_linked_to_previous assert_complex_field_value(u'N', footer_1.part.element, u'shared.footer') assert_complex_field_value(u'N', footer_2.part.element, u'shared.footer') CustomProperties(document).update_all() # the same header should be referenced by both sections assert_complex_field_value(u'ig bi obe', header_1.part.element, u'shared.header') assert_complex_field_value(u'ig bi obe', header_2.part.element, u'shared.header') # the same footer should be referenced by both sections footer_1 = document.sections[0].footer footer_2 = document.sections[1].footer assert_complex_field_value(u'Y', footer_1.part.element, u'shared.footer') assert_complex_field_value(u'Y', footer_2.part.element, u'shared.footer')
def test_date_docprops_with_format_get_updated(self): document = Document(docx_path('date_docproperties_with_format.docx')) assert len( document.paragraphs) == 3, 'input file should contain 3 paragraph' expected_values = [ u'11.06.19', u'mardi 11 juin 2019', u'11-6-19 0:0:0' ] for i, (expected, paragraph) in enumerate( zip(expected_values, document.paragraphs)): assert paragraph.text == expected CustomProperties(document).update_all() expected_values = [ u'23.01.20', u'Thursday 23 January 2020', u'23-1-20 10:0:0' ] for i, (expected, paragraph) in enumerate( zip(expected_values, document.paragraphs)): assert paragraph.text == expected, 'docprop {} was not updated correctly'.format( i + 1)
def test_removes_simple_field_but_keeps_value(self): document = Document( docx_path('outdated_docproperty_with_umlauts.docx')) assert 1 == len( document.paragraphs), 'input file should contain 1 paragraph' fields = xpath( document.element.body, u'.//w:fldSimple[contains(@w:instr, \'DOCPROPERTY "F\xfc\xfc"\')]//w:t' ) assert 1 == len(fields), 'should contain one simple field docproperty' assert u'Hie chund ds property: ' == document.paragraphs[0].text assert u'xxx' == fields[0].text CustomProperties(document).dissolve_fields(u"F\xfc\xfc") fields = xpath( document.element.body, u'.//w:fldSimple[contains(@w:instr, \'DOCPROPERTY "F\xfc\xfc"\')]//w:t' ) assert 0 == len(fields), 'should not contain any docproperties anymore' # when simple field is removed, the value is moved one up in the hierarchy assert u'Hie chund ds property: xxx' == document.paragraphs[0].text
def test_complex_field_gets_updated(self): document = Document(docx_path('docproperties.docx')) assert 6 == len(document.paragraphs), 'input file should contain 6 paragraphs' properties = xpath(document.element.body, './/w:instrText') assert 5 == len(properties),\ 'input should contain five complex field docproperties' expected_paragraphs = [u'Custom Doc Properties', u'Text: Foo Bar', u'Number: 123', u'Boolean: Y', u'Date: 11.06.2019', u'Float: 1.1'] actual_paragraphs = [paragraph.text for paragraph in document.paragraphs] assert actual_paragraphs == expected_paragraphs CustomProperties(document).update("Number Property", 423) expected_paragraphs[2] = u'Number: 423' actual_paragraphs = [paragraph.text for paragraph in document.paragraphs] assert actual_paragraphs == expected_paragraphs
def test_dissolving_field_when_three_complex_docprop_in_same_paragraph(self): document = Document(docx_path('three_props_in_same_paragraph.docx')) assert 1 == len(document.paragraphs), 'input file should contains one paragraph' paragraph = document.paragraphs[0] properties = CustomProperties(document) assert 3 == len(properties.find_docprops_in_document()), \ 'input should contain three complex field docproperties' text = u'{text} / {num} mor between the fields {text} and some afte the three fields' assert text.format(text="I was spellcecked", num=0) == paragraph.text properties.dissolve_fields("Text Property") assert 1 == len(document.paragraphs) assert 1 == len(properties.find_docprops_in_document()), \ 'document should contain one complex field after removal' assert text.format(text="I was spellcecked", num=0) == paragraph.text
def test_docproperty_without_separate_does_not_get_updated(self): """It would probably be better to add the value to such a field during update, but that seems out of scope for now. """ document = Document(docx_path('complex_field_without_separate.docx')) custom_properties = CustomProperties(document) properties = custom_properties.find_docprops_in_document() paragraphs = document.paragraphs # Make sure that a value is set for 'User.FullName' assert ('User.FullName', 'Test User') in custom_properties.items() assert ('Dossier.Title', ' Some Title') in custom_properties.items() # Make sure that 'User.FullName' field has no separate node matches = [prop for prop in properties if prop.name == 'User.FullName'] assert 1 == len(matches), \ "There should be only one User.FullName docproperty" fullname = matches[0] assert fullname.get_separate_run() is None, \ "This complex field should not have a separate run." # Make sure that 'Dossier.Title' field has a separate node matches = [prop for prop in properties if prop.name == 'Dossier.Title'] assert 1 == len(matches), \ "There should be only one Dossier.Title docproperty" title = matches[0] assert title.get_separate_run() is not None, \ "This complex field should have a separate run." # Check the content of the paragraphs before update assert 2 == len(paragraphs) assert u'Sachbearbeiter: ' == paragraphs[0].text assert u'Sachbearbeiter: ' in fullname.w_p.xml assert u'Dossier Titel: ' == paragraphs[1].text custom_properties.update_all() # Field with missing separate was not updated assert u'Sachbearbeiter: ' == paragraphs[0].text # Next field was updated correctly assert u'Dossier Titel: Some Title' == paragraphs[1].text
def test_updates_doc_properties_different_odd_even_pages(self): document = Document(docx_path('docproperties_different_odd_even_pages_1_section.docx')) assert_simple_field_value( u'xxx', document.sections[0].header.part.element, u'odd.header') assert_simple_field_value( u'xxx', document.sections[0].footer.part.element, u'odd.footer') assert_simple_field_value( u'0', document.sections[0].even_page_header.part.element, u'even.header') assert_simple_field_value( u'Y', document.sections[0].even_page_footer.part.element, u'even.footer') CustomProperties(document).update_all() assert_simple_field_value( u'odd-header', document.sections[0].header.part.element, u'odd.header') assert_simple_field_value( u'odd-footer', document.sections[0].footer.part.element, u'odd.footer') assert_simple_field_value( u'1337', document.sections[0].even_page_header.part.element, u'even.header') assert_simple_field_value( u'N', document.sections[0].even_page_footer.part.element, u'even.footer')
def test_updates_docproperties_shared_header(self): document = Document( docx_path('docproperties_shared_header_2_sections.docx')) # the same header should be referenced by both sections # the sections should be considered as linked header_1 = document.sections[0].header header_2 = document.sections[1].header assert not header_1.is_linked_to_previous assert header_2.is_linked_to_previous assert_complex_field_value(u'xxx', header_1.part.element, u'shared.header') assert_complex_field_value(u'xxx', header_2.part.element, u'shared.header') footer_1 = document.sections[0].footer footer_2 = document.sections[1].footer assert not footer_1.is_linked_to_previous assert not footer_2.is_linked_to_previous assert_complex_field_value(u'123', footer_1.part.element, u'section1.footer') assert_complex_field_value(u'yyy', footer_2.part.element, u'section2.footer') CustomProperties(document).update_all() # the same header should be referenced by both sections assert_complex_field_value(u'sh\xe4red', header_1.part.element, u'shared.header') assert_complex_field_value(u'sh\xe4red', header_2.part.element, u'shared.header') footer_1 = document.sections[0].footer footer_2 = document.sections[1].footer assert_complex_field_value(u'-1.0', footer_1.part.element, u'section1.footer') assert_complex_field_value(u'f\xfc\xfcter', footer_2.part.element, u'section2.footer')
def test_updates_doc_properties_different_first_page(self): document = Document(docx_path('docproperties_different_first_page_1_section.docx')) assert_simple_field_value( u'xxx', document.sections[0].first_page_header.part.element, u'page1.header') assert_simple_field_value( u'xxx', document.sections[0].first_page_footer.part.element, u'page1.footer') assert_simple_field_value( u'0', document.sections[0].header.part.element, u'page2.header') assert_simple_field_value( u'01.01.1970', document.sections[0].footer.part.element, u'page2.footer') CustomProperties(document).update_all() assert_simple_field_value( u'p1h', document.sections[0].first_page_header.part.element, u'page1.header') assert_simple_field_value( u'p1f', document.sections[0].first_page_footer.part.element, u'page1.footer') assert_simple_field_value( u'42', document.sections[0].header.part.element, u'page2.header') assert_simple_field_value( u'18.10.1984', document.sections[0].footer.part.element, u'page2.footer')
def test_document_checkin_updates_doc_properties(self): manager = getMultiAdapter( (self.doc_with_gever_properties, self.request), ICheckinCheckoutManager) manager.checkout() self.set_document_property_referencenumber() manager.checkin() expected_doc_properties = [ ('Document.ReferenceNumber', 'Client1 / 1 / 1'), ('Document.SequenceNumber', '1'), ('Dossier.ReferenceNumber', 'Client1 / 1'), ('Dossier.Title', 'Dossier'), ('ogg.document.document_date', datetime(2010, 12, 30, 0, 0)), ('ogg.document.reference_number', 'Client1 / 1 / 1'), ('ogg.document.sequence_number', '1'), ('ogg.document.title', 'Document with file'), ('ogg.document.version_number', 0), ('ogg.dossier.reference_number', 'Client1 / 1'), ('ogg.dossier.sequence_number', '1'), ('ogg.dossier.title', 'Dossier'), ('ogg.user.email', '*****@*****.**'), ('ogg.user.firstname', 'User'), ('ogg.user.lastname', 'Test'), ('ogg.user.title', 'Test User'), ('ogg.user.userid', TEST_USER_ID), ('User.FullName', 'Test User'), ('User.ID', TEST_USER_ID), ] with TemporaryDocFile(self.doc_with_gever_properties.file) as tmpfile: properties = CustomProperties(Document(tmpfile.path)).items() self.assertItemsEqual(expected_doc_properties, properties) self.assert_doc_properties_updated_journal_entry_generated( self.doc_with_gever_properties, entry=-2)
def test_add_utf8_property(): document = Document(docx_path('docproperties.docx')) props = CustomProperties(document) props.add('My Text Property', u'f\xfc\xfc'.encode('utf-8')) assert props.get('My Text Property') == u'f\xfc\xfc'
def test_add_doc_properties(): document = Document(docx_path('docproperties.docx')) props = CustomProperties(document) props.add('My Text Property', 'foo bar') assert props.get('My Text Property') == 'foo bar' props.add('My Boolean Property', True) assert props.get('My Boolean Property') is True props.add('My Number Property', 123) assert props.get('My Number Property') == 123 props.add('My Date Property', datetime(2019, 10, 23, 15, 44, 50)) assert props.get('My Date Property') == datetime(2019, 10, 23, 15, 44, 50)
def test_get_doc_property_is_case_insensitive(): document = Document(docx_path('docproperties.docx')) props = CustomProperties(document) assert props['text property'] == 'Foo Bar' assert props.get('text property') == 'Foo Bar'
def test_org_role_recipient_properties_are_added(self, browser): organization = create( Builder('organization').having(name=u'Meier AG'), ) org_role = create( Builder('org_role').having( person=self.peter, organization=organization, function=u'cheffe', ), ) create( Builder('address').for_contact(organization).labeled( u'Home').having( street=u'Musterstrasse 283', zip_code=u'1234', city=u'Hinterkappelen', country=u'Schweiz', ), ) mailaddress = create( Builder('mailaddress').for_contact(organization).having( address=u'*****@*****.**'), ) phonenumber = create( Builder('phonenumber').for_contact( self.peter).having(phone_number=u'1234 123 123'), ) url = create( Builder('url').for_contact(organization).having( url=u'http://www.example.com'), ) address_id = org_role.addresses[0].address_id with freeze(self.document_date): # submit first wizard step browser.login().open(self.dossier, view='document_with_template') browser.fill({ 'form.widgets.template': self._make_token(self.template_word), 'Title': 'Test Docx', }) form = browser.find_form_by_field('Recipient') form.find_widget('Recipient').fill(get_contacts_token(org_role)) form.save() # submit second wizard step browser.fill({ 'form.widgets.address': address_id, 'form.widgets.mail_address': str(mailaddress.mailaddress_id), 'form.widgets.phonenumber': str(phonenumber.phone_number_id), 'form.widgets.url': str(url.url_id), }).save() document = self.dossier.listFolderContents()[0] self.assertEquals(u'Test Docx.docx', document.file.filename) expected_org_role_properties = { 'ogg.recipient.contact.title': u'M\xfcller Peter', 'ogg.recipient.person.firstname': 'Peter', 'ogg.recipient.person.lastname': u'M\xfcller', 'ogg.recipient.orgrole.function': u'cheffe', 'ogg.recipient.organization.name': u'Meier AG', 'ogg.recipient.address.street': u'Musterstrasse 283', 'ogg.recipient.address.zip_code': '1234', 'ogg.recipient.address.city': 'Hinterkappelen', 'ogg.recipient.address.country': 'Schweiz', 'ogg.recipient.email.address': u'*****@*****.**', 'ogg.recipient.phone.number': u'1234 123 123', 'ogg.recipient.url.url': u'http://www.example.com', } expected_org_role_properties.update(self.expected_doc_properties) with TemporaryDocFile(document.file) as tmpfile: properties = CustomProperties(Document(tmpfile.path)).items() self.assertItemsEqual(expected_org_role_properties.items(), properties) self.assert_doc_properties_updated_journal_entry_generated(document)
def test_contains_is_case_insensitive(): document = Document(docx_path('docproperties.docx')) props = CustomProperties(document) assert 'text property' in props
def test_nullify_doc_property_is_case_insensitive(): document = Document(docx_path('docproperties.docx')) props = CustomProperties(document) props.nullify('text property') assert props['Text Property'] == ''
def test_properties_are_added_when_created_from_template_without_doc_properties( self, browser): self.login(self.regular_user, browser) with freeze(datetime(2020, 10, 28, 0, 0)): browser.open(self.dossier, view='document_with_template') browser.fill({ 'form.widgets.template': str(getUtility(IIntIds).getId(self.asset_template)), 'Title': 'Test Docx', }).save() document = self.dossier.listFolderContents()[-1] self.assertEquals(u'Test Docx.docx', document.file.filename) expected_doc_properties = { 'Document.ReferenceNumber': 'Client1 1.1 / 1 / 41', 'Document.SequenceNumber': '41', 'Dossier.ReferenceNumber': 'Client1 1.1 / 1', 'Dossier.Title': u'Vertr\xe4ge mit der kantonalen Finanzverwaltung', 'User.FullName': u'B\xe4rfuss K\xe4thi', 'User.ID': 'kathi.barfuss', 'ogg.document.document_date': datetime(2020, 10, 28, 0, 0), 'ogg.document.reference_number': 'Client1 1.1 / 1 / 41', 'ogg.document.sequence_number': '41', 'ogg.document.title': 'Test Docx', 'ogg.document.version_number': 0, 'ogg.dossier.external_reference': u'qpr-900-9001-\xf7', 'ogg.dossier.reference_number': 'Client1 1.1 / 1', 'ogg.dossier.sequence_number': '1', 'ogg.dossier.title': u'Vertr\xe4ge mit der kantonalen Finanzverwaltung', 'ogg.user.address1': 'Kappelenweg 13', 'ogg.user.address2': 'Postfach 1234', 'ogg.user.city': 'Vorkappelen', 'ogg.user.country': 'Schweiz', 'ogg.user.department': 'Staatskanzlei', 'ogg.user.department_abbr': 'SK', 'ogg.user.description': 'nix', 'ogg.user.directorate': 'Staatsarchiv', 'ogg.user.directorate_abbr': 'Arch', 'ogg.user.email': '*****@*****.**', 'ogg.user.email2': '*****@*****.**', 'ogg.user.firstname': u'K\xe4thi', 'ogg.user.lastname': u'B\xe4rfuss', 'ogg.user.phone_fax': '012 34 56 77', 'ogg.user.phone_mobile': '012 34 56 76', 'ogg.user.phone_office': '012 34 56 78', 'ogg.user.salutation': 'Prof. Dr.', 'ogg.user.title': u'B\xe4rfuss K\xe4thi', 'ogg.user.url': 'http://www.example.com', 'ogg.user.userid': 'kathi.barfuss', 'ogg.user.zip_code': '1234', } with TemporaryDocFile(document.file) as tmpfile: properties = CustomProperties(Document(tmpfile.path)).items() self.assertItemsEqual(expected_doc_properties.items(), properties) self.assert_doc_properties_updated_journal_entry_generated( document, self.regular_user)
def test_nullify_doc_properties(): document = Document(docx_path('docproperties.docx')) props = CustomProperties(document) props.nullify('Text Property') props.nullify('Number Property') props.nullify('Boolean Property') props.nullify('Date Property') props.nullify('Float Property') assert props['Text Property'] == '' assert 'Number Property' not in props assert 'Boolean Property' not in props assert 'Date Property' not in props assert 'Float Property' not in props
def test_doc_properties_values(): document = Document(docx_path('docproperties.docx')) props = CustomProperties(document) assert props.values() == [ 'Foo Bar', 123, True, datetime(2019, 6, 11, 10, 0), 1.1]
def test_set_doc_property_is_case_insensitive(): document = Document(docx_path('docproperties.docx')) props = CustomProperties(document) props['text property'] = 'baz' assert props['Text Property'] == 'baz'