wipo-gbd-transformation 1.1.52__py3-none-any.whl → 1.1.53__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wipo-gbd-transformation might be problematic. Click here for more details.

Files changed (37) hide show
  1. gbdtransformation/brands/istm/filters.py +1 -2
  2. gbdtransformation/brands/vntm/filters.py +1 -3
  3. gbdtransformation/designs/alid/filters.py +13 -1
  4. gbdtransformation/designs/bgid/__init__.py +5 -0
  5. gbdtransformation/designs/bgid/filters.py +91 -0
  6. gbdtransformation/designs/bgid/schema +106 -0
  7. gbdtransformation/designs/bgid/template.yml +169 -0
  8. gbdtransformation/designs/bnid/filters.py +13 -1
  9. gbdtransformation/designs/bwid/filters.py +13 -1
  10. gbdtransformation/designs/crid/filters.py +14 -1
  11. gbdtransformation/designs/cuid/filters.py +14 -1
  12. gbdtransformation/designs/egid/filters.py +14 -1
  13. gbdtransformation/designs/filters.py +10 -3
  14. gbdtransformation/designs/idid/filters.py +14 -1
  15. gbdtransformation/designs/ipas/filters.py +83 -0
  16. gbdtransformation/designs/ipas/template.yml +15 -15
  17. gbdtransformation/designs/joid/filters.py +14 -1
  18. gbdtransformation/designs/keid/filters.py +14 -1
  19. gbdtransformation/designs/khid/filters.py +14 -1
  20. gbdtransformation/designs/laid/filters.py +13 -1
  21. gbdtransformation/designs/mnid/filters.py +14 -1
  22. gbdtransformation/designs/myid/filters.py +13 -1
  23. gbdtransformation/designs/phid/filters.py +13 -1
  24. gbdtransformation/designs/sgid/filters.py +14 -1
  25. gbdtransformation/designs/thid/filters.py +13 -1
  26. gbdtransformation/designs/tnid/filters.py +13 -1
  27. gbdtransformation/designs/vnid/filters.py +13 -1
  28. gbdtransformation/designs/woid/filters.py +21 -16
  29. gbdtransformation/designs/woid/template.yml +11 -2
  30. gbdtransformation/designs/xxid/template.yml +10 -4
  31. gbdtransformation/execs.py +3 -2
  32. {wipo_gbd_transformation-1.1.52.dist-info → wipo_gbd_transformation-1.1.53.dist-info}/METADATA +3 -3
  33. {wipo_gbd_transformation-1.1.52.dist-info → wipo_gbd_transformation-1.1.53.dist-info}/RECORD +37 -33
  34. {wipo_gbd_transformation-1.1.52.dist-info → wipo_gbd_transformation-1.1.53.dist-info}/WHEEL +1 -1
  35. {wipo_gbd_transformation-1.1.52.dist-info → wipo_gbd_transformation-1.1.53.dist-info}/LICENSE.md +0 -0
  36. {wipo_gbd_transformation-1.1.52.dist-info → wipo_gbd_transformation-1.1.53.dist-info}/entry_points.txt +0 -0
  37. {wipo_gbd_transformation-1.1.52.dist-info → wipo_gbd_transformation-1.1.53.dist-info}/top_level.txt +0 -0
@@ -35,8 +35,7 @@ def translate_status(status, status_is):
35
35
  if status == 'Expired': return 'Expired'
36
36
  if status == 'Ended': return 'Ended'
37
37
  if status == 'Registered': return 'Registered'
38
- #return 'Unknown'
39
- raise Exception('Status "%s/%s" unmapped' % (status, status_is))
38
+ return 'Unknown'
40
39
 
41
40
 
42
41
 
@@ -39,9 +39,7 @@ def translate_status(trademark):
39
39
  return ipas.translate_status("Expired")
40
40
  elif value in ['Từ bỏ', 'Mất hiệu lực']:
41
41
  return ipas.translate_status('Ended')
42
- elif value in ['465']:
43
- return 'Unknown'
44
- raise Exception('Status "%s" is not mapped.' % value)
42
+ return 'Unknown'
45
43
 
46
44
  def translate_feature(trademark):
47
45
  feature = trademark.MarkFeature
@@ -54,4 +54,16 @@ def is_international(header):
54
54
  return False
55
55
 
56
56
  def get_ir_refnum(appnum):
57
- return appnum
57
+ return appnum
58
+
59
+ def select_earliest_date(publications):
60
+ return ipas.select_earliest_date(publications)
61
+
62
+ def deduplicate_publication_dates(publications):
63
+ return ipas.deduplicate_publication_dates(publications)
64
+
65
+ def deduplicate_classes(classes):
66
+ return ipas.deduplicate_classes(classes)
67
+
68
+ def deduplicate_publications(publications):
69
+ return ipas.deduplicate_publications(publications)
@@ -0,0 +1,5 @@
1
+ render = 'JSON'
2
+ source = 'national'
3
+
4
+ # AID2018000076
5
+ appnum_mask = ['(\\d*)-(\\d*)']
@@ -0,0 +1,91 @@
1
+ # standard gdd definitions
2
+ from gbdtransformation.designs import kinds as std_kinds
3
+ from gbdtransformation.designs import status as std_status
4
+
5
+ # namespaces defined in XML and to be ignored in procecssing
6
+ ignore_namespace = [
7
+ "http://www.oami.europa.eu/schemas/design_Transaction",
8
+ "http://www.oami.europa.eu/schemas/design_IndicationProduct",
9
+ "http://www.oami.europa.eu/schemas/design",
10
+ ]
11
+
12
+ def get_appdate(appdate, appnum):
13
+ return appdate
14
+
15
+ def get_designs_count(design, header):
16
+ return '1'
17
+
18
+ def get_designs_pos(design, header):
19
+ return '1'
20
+
21
+ # -------------------------------------------------------------
22
+ # data translation helpers:
23
+ # translate values from office interpretation to gbd equivalent
24
+ # -------------------------------------------------------------
25
+ def translate_kind(desgin, header):
26
+ code = header.TransactionCode.lower()
27
+ if code == 'ds-search design list':
28
+ return 'Industrial Design'
29
+ raise Exception('Type "%s" is not mapped.' % (code))
30
+
31
+ def parseForSt13(appnum, des_ref):
32
+ if des_ref.get('DesignIdentifier'):
33
+ return appnum + '-' + des_ref['DesignIdentifier'].split('-')[1]
34
+ else:
35
+ return appnum + '-' + des_ref['DesignURI'].split('-')[1]
36
+
37
+ def format_address(address):
38
+ return '%s, %s %s' % (address.AddressStreet,
39
+ address.AddressPostcode,
40
+ address.AddressCity)
41
+
42
+ def format_name(name):
43
+ fname = name.FirstName
44
+ lname = name.LastName
45
+
46
+ full_name = [name.FirstName, name.LastName]
47
+ full_name = [f.strip() for f in full_name if f is not None]
48
+
49
+ return ' '.join(full_name)
50
+
51
+
52
+ def is_international(header):
53
+ return False
54
+
55
+ def get_ir_refnum(appnum):
56
+ return appnum
57
+
58
+ def translate_status(desgin):
59
+ if desgin._operationCode == 'Delete':
60
+ return 'Delete'
61
+
62
+ status = desgin.DesignCurrentStatusCode
63
+
64
+ if status in ['Application filed',
65
+ 'Application published',
66
+ 'Application under examination',
67
+ 'Registration pending',
68
+ 'Appeal pending',
69
+ 'Registration cancellation pending',
70
+ 'Filed']:
71
+ return 'Pending'
72
+
73
+ if status in ['Application refused',
74
+ 'Application withdrawn',
75
+ 'Application opposed',
76
+ 'Registration cancelled',
77
+ 'Registration surrendered',
78
+ 'Design surrendered',
79
+ 'Design declared invalid',
80
+ 'Lack of effects',
81
+ "Design lapsed",
82
+ 'Ended']:
83
+ return 'Ended'
84
+
85
+ if status in ['Registered',
86
+ 'Registered and subject to deferment',
87
+ 'Registered and fully published']:
88
+ return 'Registered'
89
+ if status in ['Registration expired', 'Expired']: return 'Expired'
90
+
91
+ raise Exception('Status "%s" not mapped.' % status)
@@ -0,0 +1,106 @@
1
+ /Transaction
2
+ __/DesignTransactionBody
3
+ ____/TransactionContentDetails
4
+ ______/TransactionCode
5
+ ______/TransactionData
6
+ ________/DesignDetails
7
+ __________/Design
8
+ ____________/ApplicantDetails
9
+ ______________/Applicant
10
+ ________________/ApplicantAddressBook
11
+ __________________/ContactInformationDetails
12
+ ____________________/Email
13
+ ____________________/Phone
14
+ ____________________/Phone[@phoneKind=Undefined]
15
+ __________________/FormattedNameAddress
16
+ ____________________/Address
17
+ ______________________/AddressCountryCode
18
+ ______________________/FormattedAddress
19
+ ________________________/AddressCity
20
+ ________________________/AddressCounty
21
+ ________________________/AddressPostcode
22
+ ________________________/AddressStreet
23
+ ____________________/Name
24
+ ______________________/FormattedName
25
+ ________________________/FirstName
26
+ ________________________/LastName
27
+ ________________________/MiddleName
28
+ ________________________/OrganizationName
29
+ ________________/ApplicantIdentifier
30
+ ________________/ApplicantNationalityCode
31
+ ____________/ApplicationDate
32
+ ____________/ApplicationNumber
33
+ ____________/ClassDescriptionDetails
34
+ ______________/ClassDescription
35
+ ________________/ClassNumber
36
+ ____________/DefermentExpirationDate
37
+ ____________/DesignCurrentStatusCode
38
+ ____________/DesignCurrentStatusDate
39
+ ____________/DesignIdentifier
40
+ ____________/DesignPreferedRepresentation
41
+ ______________/ViewURI
42
+ ____________/DesignRepresentationSheetDetails
43
+ ______________/DesignRepresentationSheet
44
+ ________________/ViewDetails
45
+ __________________/View
46
+ ____________________/ViewURI
47
+ ____________/DesignURI
48
+ ____________/DesignerDetails
49
+ ______________/Designer
50
+ ________________/DesignerAddressBook
51
+ __________________/FormattedNameAddress
52
+ ____________________/Name
53
+ ______________________/FreeFormatName
54
+ ________________________/FreeFormatNameDetails
55
+ __________________________/FreeFormatNameLine
56
+ ________________/DesignerIdentifier
57
+ ____________/EffectiveDate
58
+ ____________/ExpiryDate
59
+ ____________/IndicationProductDetails
60
+ ______________/IndicationProduct
61
+ ______________/IndicationProduct[@languageCode=BG]
62
+ ____________/PriorityDetails
63
+ ______________/Priority
64
+ ________________/PriorityCountryCode
65
+ ________________/PriorityDate
66
+ ________________/PriorityNumber
67
+ ____________/PublicationDate
68
+ ____________/RegistrationDate
69
+ ____________/RegistrationNumber
70
+ ____________/RegistrationOfficeCode
71
+ ____________/RepresentativeDetails
72
+ ______________/Representative
73
+ ________________/RepresentativeAddressBook
74
+ __________________/ContactInformationDetails
75
+ ____________________/Email
76
+ ____________________/Phone
77
+ ____________________/Phone[@phoneKind=Undefined]
78
+ __________________/FormattedNameAddress
79
+ ____________________/Address
80
+ ______________________/AddressCountryCode
81
+ ______________________/FormattedAddress
82
+ ________________________/AddressCity
83
+ ________________________/AddressCounty
84
+ ________________________/AddressPostcode
85
+ ________________________/AddressStreet
86
+ ____________________/Name
87
+ ______________________/FormattedName
88
+ ________________________/FirstName
89
+ ________________________/LastName
90
+ ________________________/MiddleName
91
+ ________________________/OrganizationName
92
+ ______________________/FreeFormatName
93
+ ________________________/FreeFormatNameDetails
94
+ __________________________/FreeFormatNameLine
95
+ ________________/RepresentativeIdentifier
96
+ ________________/RepresentativeKindCode
97
+ ________________/RepresentativeLegalEntity
98
+ ________________/RepresentativeNationalityCode
99
+ ________________/RepresentativeURI
100
+ __________/Design[@operationCode=Delete]
101
+ __________/Design[@operationCode=Insert]
102
+ ______/TransactionIdentifier
103
+ __/TransactionHeader
104
+ ____/SenderDetails
105
+ ______/RequestProducerDateTime
106
+ ________/design EM-DS-Search-DesignList-V1-0.xsd]
@@ -0,0 +1,169 @@
1
+ {% from 'navigation.tmpl' import match %}
2
+
3
+ {% call(header) match('DesignTransactionBody.TransactionContentDetails', Transaction) %}
4
+
5
+ {% call(design) match('TransactionData.DesignDetails.Design', header) %}
6
+ {% set design_count = design | get_designs_count(header) %}
7
+ {% set design_pos = design | get_designs_pos(header) %}
8
+ {% set kind = design | translate_kind(header) %}
9
+ type: 'DESIGN'
10
+ subtype: 'OPEN'
11
+ designGrouping: 'MULTIPLE'
12
+ designsCount: {{ design_count }}
13
+
14
+ kind:
15
+ - {{kind}}
16
+ {{ design }}
17
+ registrationOfficeCode: {{ design.RegistrationOfficeCode}}
18
+ designatedCountries:
19
+ - BG
20
+ reference:
21
+ {% if header | is_international %}
22
+ registration:
23
+ - number: {{ design.ApplicationNumber | get_ir_refnum }}
24
+ office: WO
25
+ {% endif %}
26
+ {% if not kind == 'Industrial Design' %}
27
+ registration:
28
+ - number: {{ design.RegistrationNumber }}
29
+ {% endif %}
30
+
31
+ {% set idstatus = design | translate_status %}
32
+ {% set appdate = design.ApplicationDate | get_appdate(design.ApplicationNumber) %}
33
+
34
+ st13: {{ design.ApplicationNumber | parseForSt13(design) | st13(design.RegistrationOfficeCode, design_pos, appdate=appdate) }}
35
+
36
+ applicationNumber: {{ design.ApplicationNumber }}
37
+ applicationDate: {{ design.ApplicationDate }}
38
+ registrationNumber: {{ design.RegistrationNumber }}
39
+ registrationDate: {{ design.RegistrationDate }}
40
+ publicationDate: {{ design.PublicationDate }}
41
+ expiryDate: {{ design.ExpiryDate }}
42
+
43
+ applicationLanguageCode: BG
44
+
45
+
46
+ applicants:
47
+ {% call(applicant) match('ApplicantDetails.Applicant', design) %}
48
+ - identifier: {{ applicant.ApplicantIdentifier }}
49
+ {% call(details) match('ApplicantAddressBook.FormattedNameAddress.Name.FormattedName', applicant) %}
50
+ {% if details.OrganizationName %}
51
+ kind: 'organization'
52
+ fullName:
53
+ - languageCode: BG
54
+ text: {{ details.OrganizationName }}
55
+ {% else %}
56
+ kind: 'person'
57
+ fullName:
58
+ - languageCode: BG
59
+ text: {{ details | format_name }}
60
+ firstName:
61
+ - languageCode: BG
62
+ text: {{ details.FirstName}}
63
+ lastName:
64
+ - languageCode: BG
65
+ text: {{ details.LastName}}
66
+ middleName:
67
+ - languageCode: BG
68
+ text: {{ details.MiddleName}}
69
+ {% endif %}
70
+ {% endcall %}
71
+ {% call(address) match('ApplicantAddressBook.FormattedNameAddress.Address', applicant) %}
72
+ fullAddress:
73
+ - languageCode: BG
74
+ text: {{ address.FormattedAddress | format_address }}
75
+ addressLines: {{ address.FormattedAddress.AddressStreet }}
76
+ cityName: {{ address.FormattedAddress.AddressCity }}
77
+ geographicRegionName: {{ address.FormattedAddress.AddressCounty }}
78
+ postalCode: {{ address.FormattedAddress.AddressPostcode }}
79
+ countryCode: {{ address.AddressCountryCode }}
80
+ {% endcall %}
81
+ {% endcall %}
82
+
83
+ representatives:
84
+ {% call(rep) match('RepresentativeDetails.Representative', design) %}
85
+ - identifier: {{ rep.RepresentativeIdentifier }}
86
+ {% call(details) match('RepresentativeAddressBook.FormattedNameAddress.Name.FormattedName', rep) %}
87
+ kind: {{ rep.RepresentativeLegalEntity}}
88
+ {% if details.OrganizationName %}
89
+ fullName:
90
+ - languageCode: BG
91
+ text: {{ details.OrganizationName }}
92
+ {% else %}
93
+ fullName:
94
+ - languageCode: BG
95
+ text: {{ details | format_name }}
96
+ firstName:
97
+ - languageCode: BG
98
+ text: {{ details.FirstName}}
99
+ lastName:
100
+ - languageCode: BG
101
+ text: {{ details.LastName}}
102
+ middleName:
103
+ - languageCode: BG
104
+ text: {{ details.MiddleName}}
105
+ {% endif %}
106
+ {% endcall %}
107
+ {% call(address) match('RepresentativeAddressBook.FormattedNameAddress.Address', rep) %}
108
+ fullAddress:
109
+ - languageCode: BG
110
+ text: {{ address.FormattedAddress | format_address }}
111
+ addressLines: {{ address.FormattedAddress.AddressStreet }}
112
+ cityName: {{ address.FormattedAddress.AddressCity }}
113
+ geographicRegionName: {{ address.FormattedAddress.AddressCounty }}
114
+ postalCode: {{ address.FormattedAddress.AddressPostcode }}
115
+ countryCode: {{ address.AddressCountryCode }}
116
+ {% endcall %}
117
+ {% endcall %}
118
+
119
+ designs:
120
+ - designPos: {{ design_pos }}
121
+ officeStatus: {{ design.DesignCurrentStatusCode | parseStatus }}
122
+ gbdStatus: {{ idstatus }}
123
+ statusDate: {{ design.DesignCurrentStatusDate }}
124
+ productIndication:
125
+ {% call(indic) match('IndicationProduct', design.IndicationProductDetails) %}
126
+ - languageCode: {{ indic | guess_language(indic._languageCode, BG) }}
127
+ text: {{ indic }}
128
+ {% endcall %}
129
+
130
+ designImageDetails:
131
+ {% call(sheet) match('DesignRepresentationSheet', design.DesignRepresentationSheetDetails) %}
132
+ {% call(img) match('ViewDetails.View',sheet) %}
133
+ - name: {{ img.ViewURI }}
134
+ {% endcall %}
135
+ {% endcall %}
136
+
137
+ designer:
138
+ {% call(designer) match('DesignerDetails.Designer', design) %}
139
+ {% call(details) match('DesignerAddressBook.FormattedNameAddress.Name.FreeFormatName', designer) %}
140
+ - identifier: {{ designer.DesignerIdentifier }}
141
+ fullName:
142
+ {% call(nameline) match('FreeFormatNameDetails.FreeFormatNameLine', details) %}
143
+ - text: {{ nameline }}
144
+ languageCode: BG
145
+ {% endcall %}
146
+ {% endcall %}
147
+ {% endcall %}
148
+
149
+ productIndicationClasses:
150
+ {% call(indicationProducts) match('ClassDescriptionDetails', design) %}
151
+ - kind: "Locarno"
152
+ classes:
153
+ {% call(code) match('ClassDescription', indicationProducts) %}
154
+ - code: {{ code.ClassNumber }}
155
+ {% endcall %}
156
+ {% endcall %}
157
+
158
+ priorities:
159
+ {% call(priority) match('PriorityDetails.Priority', design) %}
160
+ - countryCode: {{ priority.PriorityCountryCode }}
161
+ number: {{ priority.PriorityNumber }}
162
+ date: {{ priority.PriorityDate }}
163
+ {% endcall %}
164
+
165
+
166
+
167
+
168
+ {% endcall %}
169
+ {% endcall %}
@@ -46,4 +46,16 @@ def is_international(header):
46
46
  return False
47
47
 
48
48
  def get_ir_refnum(appnum):
49
- return appnum
49
+ return appnum
50
+
51
+ def select_earliest_date(publications):
52
+ return ipas.select_earliest_date(publications)
53
+
54
+ def deduplicate_publication_dates(publications):
55
+ return ipas.deduplicate_publication_dates(publications)
56
+
57
+ def deduplicate_classes(classes):
58
+ return ipas.deduplicate_classes(classes)
59
+
60
+ def deduplicate_publications(publications):
61
+ return ipas.deduplicate_publications(publications)
@@ -49,4 +49,16 @@ def is_international(header):
49
49
  return False
50
50
 
51
51
  def get_ir_refnum(appnum):
52
- return appnum
52
+ return appnum
53
+
54
+ def select_earliest_date(publications):
55
+ return ipas.select_earliest_date(publications)
56
+
57
+ def deduplicate_publication_dates(publications):
58
+ return ipas.deduplicate_publication_dates(publications)
59
+
60
+ def deduplicate_classes(classes):
61
+ return ipas.deduplicate_classes(classes)
62
+
63
+ def deduplicate_publications(publications):
64
+ return ipas.deduplicate_publications(publications)
@@ -47,4 +47,17 @@ def is_international(header):
47
47
  return False
48
48
 
49
49
  def get_ir_refnum(appnum):
50
- return appnum
50
+ return appnum
51
+
52
+ def select_earliest_date(publications):
53
+ return ipas.select_earliest_date(publications)
54
+
55
+ def deduplicate_publication_dates(publications):
56
+ return ipas.deduplicate_publication_dates(publications)
57
+
58
+ def deduplicate_classes(classes):
59
+ return ipas.deduplicate_classes(classes)
60
+
61
+ def deduplicate_publications(publications):
62
+ return ipas.deduplicate_publications(publications)
63
+
@@ -44,4 +44,17 @@ def is_international(header):
44
44
  return False
45
45
 
46
46
  def get_ir_refnum(appnum):
47
- return appnum
47
+ return appnum
48
+
49
+ def select_earliest_date(publications):
50
+ return ipas.select_earliest_date(publications)
51
+
52
+ def deduplicate_publication_dates(publications):
53
+ return ipas.deduplicate_publication_dates(publications)
54
+
55
+ def deduplicate_classes(classes):
56
+ return ipas.deduplicate_classes(classes)
57
+
58
+ def deduplicate_publications(publications):
59
+ return ipas.deduplicate_publications(publications)
60
+
@@ -46,4 +46,17 @@ def is_international(header):
46
46
  return False
47
47
 
48
48
  def get_ir_refnum(appnum):
49
- return appnum
49
+ return appnum
50
+
51
+ def select_earliest_date(publications):
52
+ return ipas.select_earliest_date(publications)
53
+
54
+ def deduplicate_publication_dates(publications):
55
+ return ipas.deduplicate_publication_dates(publications)
56
+
57
+ def deduplicate_classes(classes):
58
+ return ipas.deduplicate_classes(classes)
59
+
60
+ def deduplicate_publications(publications):
61
+ return ipas.deduplicate_publications(publications)
62
+
@@ -18,9 +18,16 @@ def should_display_language(lang, payload):
18
18
  return lang
19
19
  return None
20
20
 
21
- def st13(appnum, office, pos, type='Design', appdate=None, roffice=None, sanitize=True):
21
+ def st13(appnum, registration_number, office, pos, type='Design', appdate=None, roffice=None, sanitize=True):
22
22
  if not appnum:
23
- return None
23
+ # fallback to registration number (required for example by Hague pre-1999 records, which have no application number)
24
+ if registration_number:
25
+ # remove non digit prefix (we want to keep non digit char at the end of the registration number, to distinguish
26
+ # non unitary registration numbers from the same application, e.g. D054966 and D054966A)
27
+ registration_number = re.sub(r"^[^0-9]+", '', registration_number)
28
+ appnum = 'R' + registration_number
29
+ else:
30
+ return None
24
31
  # collections are usually office code followed with tm: xxtm
25
32
  collection = '%sid' % office.lower()
26
33
 
@@ -63,4 +70,4 @@ def st13(appnum, office, pos, type='Design', appdate=None, roffice=None, sanitiz
63
70
  st13 = '%s%s' % (st13, appdate[:4])
64
71
 
65
72
  # add application number and zfill till 17
66
- return '%s%s.%s' % (st13, appnum.zfill(17 - len(st13)), pos)
73
+ return '%s%s' % (st13, appnum.zfill(17 - len(st13)))
@@ -51,4 +51,17 @@ def is_international(header):
51
51
  return False
52
52
 
53
53
  def get_ir_refnum(appnum):
54
- return appnum
54
+ return appnum
55
+
56
+ def select_earliest_date(publications):
57
+ return ipas.select_earliest_date(publications)
58
+
59
+ def deduplicate_publication_dates(publications):
60
+ return ipas.deduplicate_publication_dates(publications)
61
+
62
+ def deduplicate_classes(classes):
63
+ return ipas.deduplicate_classes(classes)
64
+
65
+ def deduplicate_publications(publications):
66
+ return ipas.deduplicate_publications(publications)
67
+
@@ -64,6 +64,89 @@ def get_registration_date(trademark, tmstatus):
64
64
  if event.MarkEventCode == 'Published':
65
65
  return event.MarkEventDate
66
66
 
67
+ # given a list of dates as strings, e.g. publication dates, deduplicate
68
+ def deduplicate_dates(dates):
69
+ return list(set(dates))
70
+
71
+ # given a list of publications, deduplicate
72
+ def deduplicate_publication_dates(design):
73
+ if design == None:
74
+ return None
75
+ dates = []
76
+ if "PublicationDetails" in design:
77
+ publicationDetails = design["PublicationDetails"]
78
+ publications = publicationDetails.get('Publication', [])
79
+ if not isinstance(publications, list):
80
+ publications = [publications]
81
+ for publication in publications:
82
+ if "PublicationDate" in publication:
83
+ dates.append(publication["PublicationDate"])
84
+ return deduplicate_dates(dates)
85
+
86
+ # given a list of classes, deduplicate
87
+ def deduplicate_classes(classes):
88
+ deduplicate_classes = []
89
+ if not isinstance(classes, list):
90
+ classes = [classes]
91
+ for the_class in classes:
92
+ if the_class["ClassNumber"] not in deduplicate_classes:
93
+ deduplicate_classes.append(the_class["ClassNumber"])
94
+ result = []
95
+ for deduplicate_class in deduplicate_classes:
96
+ result.append({ "code": deduplicate_class} )
97
+ return result
98
+
99
+ # given a list of publications, deduplicate
100
+ def deduplicate_publications(publications):
101
+ deduplicate_publications = []
102
+ pub_keys = []
103
+ if not isinstance(publications, list):
104
+ publications = [publications]
105
+ for publication in publications:
106
+ publication_date = publication.get("PublicationDate")
107
+ publication_identifier = publication.get("PublicationIdentifier")
108
+ pub_key = ""
109
+ if publication_identifier:
110
+ pub_key += publication_identifier
111
+ if publication_date:
112
+ pub_key += publication_date
113
+ if pub_key not in pub_keys:
114
+ deduplicate_publications.append(publication)
115
+ pub_keys.append(pub_key)
116
+ result = []
117
+ for publication in deduplicate_publications:
118
+ res = {}
119
+ if "PublicationIdentifier" in publication:
120
+ res["identifier"] = publication["PublicationIdentifier"]
121
+ if "PublicationDate" in publication:
122
+ res["date"] = publication["PublicationDate"]
123
+ result.append(res)
124
+ return result
125
+
126
+ # given a list of publications with dates as strings, select the earliest date publication
127
+ def select_earliest_date(design):
128
+ if design == None:
129
+ return None
130
+
131
+ if "PublicationDetails" in design:
132
+ publicationDetails = design["PublicationDetails"]
133
+ publications = publicationDetails.get('Publication', [])
134
+ if not isinstance(publications, list):
135
+ publications = [publications]
136
+ if len(publications) == 0:
137
+ return None
138
+ elif len(publications) == 1:
139
+ return publications[0]["PublicationDate"]
140
+ else:
141
+ earliest_date = None
142
+ n = -1
143
+ for count, publication in enumerate(publications):
144
+ if earliest_date == None or publication["PublicationDate"] < earliest_date:
145
+ earliest_date = publication["PublicationDate"]
146
+ return earliest_date
147
+ else:
148
+ return None
149
+
67
150
  def translate_status(status):
68
151
  status = status.lower()
69
152