diff options
Diffstat (limited to 'ishtar_common')
| -rw-r--r-- | ishtar_common/data_importer.py | 9 | ||||
| -rw-r--r-- | ishtar_common/locale/django.pot | 742 | ||||
| -rw-r--r-- | ishtar_common/models.py | 30 | ||||
| -rw-r--r-- | ishtar_common/templates/blocks/JQueryJqGrid.html | 19 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/blocks/advanced_shortcut_menu.html | 2 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/blocks/shortcut_menu.html | 2 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/wizard/validation_bar.html | 8 | ||||
| -rw-r--r-- | ishtar_common/tests.py | 66 | ||||
| -rw-r--r-- | ishtar_common/utils.py | 20 | ||||
| -rw-r--r-- | ishtar_common/views.py | 51 | ||||
| -rw-r--r-- | ishtar_common/wizards.py | 92 | 
11 files changed, 583 insertions, 458 deletions
| diff --git a/ishtar_common/data_importer.py b/ishtar_common/data_importer.py index 426d32a7a..34394341c 100644 --- a/ishtar_common/data_importer.py +++ b/ishtar_common/data_importer.py @@ -450,10 +450,11 @@ class TypeFormater(StrChoiceFormater):          self.match_table = {}          self.new_keys = {}          self.import_instance = import_instance -        for item in model.objects.all(): -            self.choices.append((item.pk, unicode(item))) -            for key in item.get_keys(importer_id=import_instance.pk): -                self.equiv_dict[key] = item +        if self.import_instance: +            for item in model.objects.all(): +                self.choices.append((item.pk, unicode(item))) +                for key in item.get_keys(importer_id=import_instance.pk): +                    self.equiv_dict[key] = item      def prepare(self, value):          return slugify(unicode(value).strip()) diff --git a/ishtar_common/locale/django.pot b/ishtar_common/locale/django.pot index 7efeabbef..207642972 100644 --- a/ishtar_common/locale/django.pot +++ b/ishtar_common/locale/django.pot @@ -25,121 +25,125 @@ msgstr ""  msgid "Export selected as CSV file"  msgstr "" -#: data_importer.py:183 +#: data_importer.py:186  #, python-format  msgid "\"%(value)s\" is too long. The max length is %(length)d characters."  msgstr "" -#: data_importer.py:200 +#: data_importer.py:203  #, python-format  msgid "\"%(value)s\" not equal to yes or no"  msgstr "" -#: data_importer.py:212 +#: data_importer.py:215  #, python-format  msgid "\"%(value)s\" is not a float"  msgstr "" -#: data_importer.py:225 data_importer.py:239 data_importer.py:483 +#: data_importer.py:228 data_importer.py:242 data_importer.py:495  #, python-format  msgid "\"%(value)s\" is not a valid date"  msgstr "" -#: data_importer.py:252 +#: data_importer.py:255  #, python-format  msgid "\"%(value)s\" is not an integer"  msgstr "" -#: data_importer.py:303 data_importer.py:546 +#: data_importer.py:312 data_importer.py:560  #, python-format  msgid "Choice for \"%s\" is not available. Which one is relevant?\n"  msgstr "" -#: data_importer.py:310 +#: data_importer.py:319  #, python-format  msgid "%d. None of the above - create new"  msgstr "" -#: data_importer.py:313 +#: data_importer.py:322  #, python-format  msgid "%d. None of the above - skip"  msgstr "" -#: data_importer.py:509 +#: data_importer.py:521  #, python-format  msgid "\"%(value)s\" is not a valid path for the given archive"  msgstr "" -#: data_importer.py:623 +#: data_importer.py:637  msgid ""  "The given file is not correct. Check the file format. If you use a CSV file: "  "check that column separator and encoding are similar to the ones used by the "  "reference file."  msgstr "" -#: data_importer.py:627 +#: data_importer.py:641  #, python-format  msgid "Too many cols (%(user_col)d) when maximum is %(ref_col)d"  msgstr "" -#: data_importer.py:629 +#: data_importer.py:643  msgid "No data provided"  msgstr "" -#: data_importer.py:630 +#: data_importer.py:644  msgid "Value is required"  msgstr "" -#: data_importer.py:631 +#: data_importer.py:645  #, python-format  msgid "At least %d columns must be filled"  msgstr "" -#: data_importer.py:632 +#: data_importer.py:646  msgid "The regexp doesn't match."  msgstr "" -#: data_importer.py:634 +#: data_importer.py:648  msgid ""  "Forced creation is set for model {} but this model is not in the list of "  "models allowed to be created."  msgstr "" -#: data_importer.py:636 +#: data_importer.py:650  msgid ""  "{} with values {} doesn't exist in the database. Create it first or fix your "  "source file."  msgstr "" -#: data_importer.py:1089 +#: data_importer.py:1103  msgid "Not imported"  msgstr "" -#: data_importer.py:1522 +#: data_importer.py:1240 +msgid "Importer configuration error: field \"{}\" does not exist for {}." +msgstr "" + +#: data_importer.py:1548  msgid "line"  msgstr "" -#: data_importer.py:1522 +#: data_importer.py:1548  msgid "col"  msgstr "" -#: data_importer.py:1522 +#: data_importer.py:1548  msgid "error"  msgstr "" -#: data_importer.py:1528 +#: data_importer.py:1554  msgid "field"  msgstr "" -#: data_importer.py:1528 +#: data_importer.py:1554  msgid "source"  msgstr "" -#: data_importer.py:1528 +#: data_importer.py:1554  msgid "result"  msgstr "" -#: data_importer.py:1544 +#: data_importer.py:1570  #, python-format  msgid "\"%(value)s\" not in %(values)s"  msgstr "" @@ -148,7 +152,7 @@ msgstr ""  msgid "Enter a valid name consisting of letters, spaces and hyphens."  msgstr "" -#: forms.py:89 forms_common.py:618 +#: forms.py:89 forms_common.py:626  msgid "Confirm"  msgstr "" @@ -172,12 +176,12 @@ msgstr ""  msgid "Add a new item"  msgstr "" -#: forms.py:262 models.py:1475 +#: forms.py:262 models.py:1482  msgid "Template"  msgstr "" -#: forms_common.py:41 forms_common.py:59 forms_common.py:182 -#: forms_common.py:406 models.py:1541 models.py:2953 +#: forms_common.py:41 forms_common.py:59 forms_common.py:184 +#: forms_common.py:408 models.py:1548 models.py:2977  #: templates/blocks/JQueryAdvancedTown.html:19  #: templates/ishtar/sheet_organization.html:13  msgid "Town" @@ -193,8 +197,8 @@ msgid ""  "french town Saint-Denis in the Seine-Saint-Denis department.</p>"  msgstr "" -#: forms_common.py:68 forms_common.py:855 ishtar_menu.py:47 models.py:2577 -#: models.py:2759 models.py:2821 templates/ishtar/sheet_person.html:4 +#: forms_common.py:68 forms_common.py:863 ishtar_menu.py:47 models.py:2599 +#: models.py:2781 models.py:2845 templates/ishtar/sheet_person.html:4  msgid "Person"  msgstr "" @@ -204,64 +208,64 @@ msgid ""  "possible."  msgstr "" -#: forms_common.py:170 forms_common.py:327 forms_common.py:451 -#: ishtar_menu.py:75 models.py:2460 models.py:2551 +#: forms_common.py:172 forms_common.py:329 forms_common.py:453 +#: ishtar_menu.py:75 models.py:2482 models.py:2573  #: templates/ishtar/sheet_organization.html:4  msgid "Organization"  msgstr "" -#: forms_common.py:173 forms_common.py:210 forms_common.py:322 -#: forms_common.py:376 forms_common.py:446 models.py:1096 models.py:1474 -#: models.py:1742 models.py:1758 models.py:1984 models.py:2454 models.py:2563 -#: models.py:2939 templates/ishtar/sheet_organization.html:8 +#: forms_common.py:175 forms_common.py:212 forms_common.py:324 +#: forms_common.py:378 forms_common.py:448 models.py:1103 models.py:1481 +#: models.py:1749 models.py:1765 models.py:1993 models.py:2476 models.py:2585 +#: models.py:2963 templates/ishtar/sheet_organization.html:8  #: templates/ishtar/sheet_organization.html:21  msgid "Name"  msgstr "" -#: forms_common.py:174 models.py:1696 models.py:2115 +#: forms_common.py:176 models.py:1703 models.py:2124  msgid "Organization type"  msgstr "" -#: forms_common.py:176 forms_common.py:400 models.py:1536 +#: forms_common.py:178 forms_common.py:402 models.py:1543  #: templates/ishtar/sheet_organization.html:10  msgid "Address"  msgstr "" -#: forms_common.py:178 forms_common.py:403 models.py:1537 +#: forms_common.py:180 forms_common.py:405 models.py:1544  #: templates/ishtar/sheet_organization.html:11  msgid "Address complement"  msgstr "" -#: forms_common.py:180 forms_common.py:404 models.py:1539 +#: forms_common.py:182 forms_common.py:406 models.py:1546  #: templates/ishtar/sheet_organization.html:12  msgid "Postal code"  msgstr "" -#: forms_common.py:183 forms_common.py:407 models.py:1542 +#: forms_common.py:185 forms_common.py:409 models.py:1549  msgid "Country"  msgstr "" -#: forms_common.py:185 forms_common.py:324 forms_common.py:380 -#: forms_common.py:448 forms_common.py:572 models.py:1569 +#: forms_common.py:187 forms_common.py:326 forms_common.py:382 +#: forms_common.py:450 forms_common.py:574 models.py:1576  msgid "Email"  msgstr "" -#: forms_common.py:186 forms_common.py:383 models.py:1554 +#: forms_common.py:188 forms_common.py:385 models.py:1561  #: templates/ishtar/sheet_organization.html:14  #: templates/ishtar/sheet_person.html:19  #: templates/ishtar/wizard/wizard_person.html:17  msgid "Phone"  msgstr "" -#: forms_common.py:187 forms_common.py:392 models.py:1566 +#: forms_common.py:189 forms_common.py:394 models.py:1573  #: templates/ishtar/sheet_organization.html:15  #: templates/ishtar/sheet_person.html:37  #: templates/ishtar/wizard/wizard_person.html:35  msgid "Mobile phone"  msgstr "" -#: forms_common.py:211 forms_common.py:325 forms_common.py:449 models.py:2151 -#: models.py:2456 models.py:2874 templates/sheet_ope.html:85 +#: forms_common.py:213 forms_common.py:327 forms_common.py:451 models.py:2160 +#: models.py:2478 models.py:2898 templates/sheet_ope.html:85  #: templates/sheet_ope.html.py:105 templates/sheet_ope.html:126  #: templates/ishtar/import_list.html:13  #: templates/ishtar/sheet_organization.html:23 @@ -269,241 +273,241 @@ msgstr ""  msgid "Type"  msgstr "" -#: forms_common.py:220 views.py:146 +#: forms_common.py:222 views.py:147  msgid "Organization search"  msgstr "" -#: forms_common.py:244 +#: forms_common.py:246  msgid "At least two items have to be selected."  msgstr "" -#: forms_common.py:262 +#: forms_common.py:264  msgid "Merge all items into"  msgstr "" -#: forms_common.py:296 +#: forms_common.py:298  msgid "Organization to merge"  msgstr "" -#: forms_common.py:323 forms_common.py:374 forms_common.py:447 models.py:2561 +#: forms_common.py:325 forms_common.py:376 forms_common.py:449 models.py:2583  #: templates/ishtar/sheet_organization.html:22  msgid "Surname"  msgstr "" -#: forms_common.py:339 forms_common.py:434 views.py:111 +#: forms_common.py:341 forms_common.py:436 views.py:112  msgid "Person search"  msgstr "" -#: forms_common.py:351 +#: forms_common.py:353  msgid "Person to merge"  msgstr "" -#: forms_common.py:368 templates/ishtar/sheet_person.html:7 +#: forms_common.py:370 templates/ishtar/sheet_person.html:7  #: templates/ishtar/wizard/wizard_person.html:6  msgid "Identity"  msgstr "" -#: forms_common.py:371 forms_common.py:773 forms_common.py:822 models.py:2116 -#: models.py:2555 models.py:2557 models.py:2871 templates/sheet_ope.html:104 +#: forms_common.py:373 forms_common.py:781 forms_common.py:830 models.py:2125 +#: models.py:2577 models.py:2579 models.py:2895 templates/sheet_ope.html:104  #: templates/ishtar/blocks/window_tables/documents.html:7  msgid "Title"  msgstr "" -#: forms_common.py:372 models.py:2559 +#: forms_common.py:374 models.py:2581  msgid "Salutation"  msgstr "" -#: forms_common.py:378 models.py:2565 +#: forms_common.py:380 models.py:2587  msgid "Raw name"  msgstr "" -#: forms_common.py:381 models.py:1555 +#: forms_common.py:383 models.py:1562  msgid "Phone description"  msgstr "" -#: forms_common.py:384 models.py:1557 models.py:1559 +#: forms_common.py:386 models.py:1564 models.py:1566  msgid "Phone description 2"  msgstr "" -#: forms_common.py:386 +#: forms_common.py:388  msgid "Phone 2"  msgstr "" -#: forms_common.py:388 models.py:1563 +#: forms_common.py:390 models.py:1570  msgid "Phone description 3"  msgstr "" -#: forms_common.py:390 models.py:1561 +#: forms_common.py:392 models.py:1568  msgid "Phone 3"  msgstr "" -#: forms_common.py:395 +#: forms_common.py:397  msgid "Current organization"  msgstr "" -#: forms_common.py:409 models.py:1544 +#: forms_common.py:411 models.py:1551  msgid "Other address: address"  msgstr "" -#: forms_common.py:412 models.py:1547 +#: forms_common.py:414 models.py:1554  msgid "Other address: address complement"  msgstr "" -#: forms_common.py:414 models.py:1548 +#: forms_common.py:416 models.py:1555  msgid "Other address: postal code"  msgstr "" -#: forms_common.py:416 models.py:1550 +#: forms_common.py:418 models.py:1557  msgid "Other address: town"  msgstr "" -#: forms_common.py:418 models.py:1552 +#: forms_common.py:420 models.py:1559  msgid "Other address: country"  msgstr "" -#: forms_common.py:430 +#: forms_common.py:432  msgid "Already has an account"  msgstr "" -#: forms_common.py:445 +#: forms_common.py:447  msgid "Username"  msgstr "" -#: forms_common.py:463 +#: forms_common.py:465  msgid "Account search"  msgstr "" -#: forms_common.py:510 forms_common.py:550 forms_common.py:554 models.py:2508 +#: forms_common.py:512 forms_common.py:552 forms_common.py:556 models.py:2530  msgid "Person type"  msgstr "" -#: forms_common.py:566 forms_common.py:571 ishtar_menu.py:32 +#: forms_common.py:568 forms_common.py:573 ishtar_menu.py:32  msgid "Account"  msgstr "" -#: forms_common.py:575 wizards.py:1281 +#: forms_common.py:577 wizards.py:1305  msgid "New password"  msgstr "" -#: forms_common.py:578 +#: forms_common.py:580  msgid "New password (confirmation)"  msgstr "" -#: forms_common.py:599 +#: forms_common.py:607  msgid "Your password and confirmation password do not match."  msgstr "" -#: forms_common.py:604 +#: forms_common.py:612  msgid "You must provide a correct password."  msgstr "" -#: forms_common.py:612 +#: forms_common.py:620  msgid "This username already exists."  msgstr "" -#: forms_common.py:619 +#: forms_common.py:627  msgid "Send the new password by email?"  msgstr "" -#: forms_common.py:628 forms_common.py:641 models.py:2954 +#: forms_common.py:636 forms_common.py:649 models.py:2978  msgid "Towns"  msgstr "" -#: forms_common.py:638 +#: forms_common.py:646  msgid "There are identical towns."  msgstr "" -#: forms_common.py:722 +#: forms_common.py:730  msgid "Only one choice can be checked."  msgstr "" -#: forms_common.py:770 +#: forms_common.py:778  msgid "Documentation informations"  msgstr "" -#: forms_common.py:775 forms_common.py:823 models.py:2117 models.py:2846 +#: forms_common.py:783 forms_common.py:831 models.py:2126 models.py:2870  msgid "Source type"  msgstr "" -#: forms_common.py:777 forms_common.py:824 templates/sheet_ope.html:84 +#: forms_common.py:785 forms_common.py:832 templates/sheet_ope.html:84  msgid "Reference"  msgstr "" -#: forms_common.py:780 forms_common.py:825 +#: forms_common.py:788 forms_common.py:833  msgid "Internal reference"  msgstr "" -#: forms_common.py:783 models.py:2885 +#: forms_common.py:791 models.py:2909  msgid "Numerical ressource (web address)"  msgstr "" -#: forms_common.py:784 models.py:2887 +#: forms_common.py:792 models.py:2911  msgid "Receipt date"  msgstr "" -#: forms_common.py:786 models.py:2283 models.py:2889 +#: forms_common.py:794 models.py:2292 models.py:2913  msgid "Creation date"  msgstr "" -#: forms_common.py:789 models.py:2892 +#: forms_common.py:797 models.py:2916  msgid "Receipt date in documentation"  msgstr "" -#: forms_common.py:791 forms_common.py:827 models.py:377 models.py:689 -#: models.py:2011 models.py:2569 models.py:2899 +#: forms_common.py:799 forms_common.py:835 models.py:379 models.py:696 +#: models.py:2020 models.py:2591 models.py:2923  msgid "Comment"  msgstr "" -#: forms_common.py:793 forms_common.py:826 models.py:1098 models.py:1762 -#: models.py:1943 models.py:1985 models.py:2898 templates/sheet_ope.html:128 +#: forms_common.py:801 forms_common.py:834 models.py:1105 models.py:1769 +#: models.py:1952 models.py:1994 models.py:2922 templates/sheet_ope.html:128  msgid "Description"  msgstr "" -#: forms_common.py:796 models.py:2900 +#: forms_common.py:804 models.py:2924  msgid "Additional information"  msgstr "" -#: forms_common.py:798 forms_common.py:830 models.py:2902 +#: forms_common.py:806 forms_common.py:838 models.py:2926  msgid "Has a duplicate"  msgstr "" -#: forms_common.py:801 +#: forms_common.py:809  msgid "Image"  msgstr "" -#: forms_common.py:802 +#: forms_common.py:810  #, python-format  msgid ""  "<p>Heavy images are resized to: %(width)dx%(height)d (ratio is preserved).</"  "p>"  msgstr "" -#: forms_common.py:819 forms_common.py:848 forms_common.py:882 models.py:2826 +#: forms_common.py:827 forms_common.py:856 forms_common.py:890 models.py:2850  #: templates/ishtar/wizard/wizard_person_deletion.html:124  msgid "Author"  msgstr "" -#: forms_common.py:829 +#: forms_common.py:837  msgid "Additional informations"  msgstr "" -#: forms_common.py:840 +#: forms_common.py:848  msgid "Would you like to delete this documentation?"  msgstr "" -#: forms_common.py:856 models.py:2118 models.py:2813 models.py:2823 +#: forms_common.py:864 models.py:2127 models.py:2837 models.py:2847  msgid "Author type"  msgstr "" -#: forms_common.py:875 +#: forms_common.py:883  msgid "Author selection"  msgstr "" -#: forms_common.py:889 +#: forms_common.py:897  msgid "There are identical authors."  msgstr "" -#: forms_common.py:893 models.py:2827 models.py:2881 +#: forms_common.py:901 models.py:2851 models.py:2905  #: templates/sheet_ope.html:106  #: templates/ishtar/blocks/window_tables/documents.html:9  msgid "Authors" @@ -521,7 +525,7 @@ msgstr ""  msgid "Deletion"  msgstr "" -#: ishtar_menu.py:39 models.py:1270 views.py:1549 +#: ishtar_menu.py:39 models.py:1277 views.py:1574  msgid "Global variables"  msgstr "" @@ -549,278 +553,278 @@ msgstr ""  msgid "Manual merge"  msgstr "" -#: ishtar_menu.py:109 models.py:2294 +#: ishtar_menu.py:109 models.py:2303  msgid "Imports"  msgstr "" -#: ishtar_menu.py:112 views.py:1557 +#: ishtar_menu.py:112 views.py:1582  msgid "New import"  msgstr "" -#: ishtar_menu.py:116 views.py:1571 +#: ishtar_menu.py:116 views.py:1596  msgid "Current imports"  msgstr "" -#: ishtar_menu.py:120 views.py:1607 +#: ishtar_menu.py:120 views.py:1632  msgid "Old imports"  msgstr "" -#: models.py:184 +#: models.py:186  msgid "Not a valid item."  msgstr "" -#: models.py:197 +#: models.py:199  msgid "A selected item is not a valid item."  msgstr "" -#: models.py:208 +#: models.py:210  msgid "This item already exists."  msgstr "" -#: models.py:373 models.py:688 models.py:1509 models.py:1521 models.py:1940 +#: models.py:375 models.py:695 models.py:1516 models.py:1528 models.py:1949  msgid "Label"  msgstr "" -#: models.py:375 +#: models.py:377  msgid "Textual ID"  msgstr "" -#: models.py:378 models.py:691 models.py:1478 +#: models.py:380 models.py:698 models.py:1485  msgid "Available"  msgstr "" -#: models.py:715 models.py:2057 +#: models.py:722 models.py:2066  msgid "Key"  msgstr "" -#: models.py:721 +#: models.py:728  msgid "Specific key to an import"  msgstr "" -#: models.py:813 +#: models.py:820  msgid "Last editor"  msgstr "" -#: models.py:816 +#: models.py:823  msgid "Creator"  msgstr "" -#: models.py:958 models.py:2965 models.py:3021 +#: models.py:965 models.py:2989 models.py:3045  msgid "Order"  msgstr "" -#: models.py:959 +#: models.py:966  msgid "Symmetrical"  msgstr "" -#: models.py:960 +#: models.py:967  msgid "Tiny label"  msgstr "" -#: models.py:974 +#: models.py:981  msgid "Cannot have symmetrical and an inverse_relation"  msgstr "" -#: models.py:1090 +#: models.py:1097  msgid "Euro"  msgstr "" -#: models.py:1091 +#: models.py:1098  msgid "US dollar"  msgstr "" -#: models.py:1097 models.py:1760 +#: models.py:1104 models.py:1767  msgid "Slug"  msgstr "" -#: models.py:1100 +#: models.py:1107  msgid "CSS color code for base module"  msgstr "" -#: models.py:1102 +#: models.py:1109  msgid "Files module"  msgstr "" -#: models.py:1104 +#: models.py:1111  msgid "CSS color code for files module"  msgstr "" -#: models.py:1106 +#: models.py:1113  msgid "Context records module"  msgstr "" -#: models.py:1109 +#: models.py:1116  msgid "CSS color code for context record module"  msgstr "" -#: models.py:1111 +#: models.py:1118  msgid "Finds module"  msgstr "" -#: models.py:1112 +#: models.py:1119  msgid "Need context records module"  msgstr "" -#: models.py:1114 +#: models.py:1121  msgid "CSS color code for find module"  msgstr "" -#: models.py:1117 +#: models.py:1124  msgid "Warehouses module"  msgstr "" -#: models.py:1118 +#: models.py:1125  msgid "Need finds module"  msgstr "" -#: models.py:1120 +#: models.py:1127  msgid "CSS code for warehouse module"  msgstr "" -#: models.py:1122 +#: models.py:1129  msgid "Mapping module"  msgstr "" -#: models.py:1124 +#: models.py:1131  msgid "CSS code for mapping module"  msgstr "" -#: models.py:1127 +#: models.py:1134  msgid "Home page"  msgstr "" -#: models.py:1128 +#: models.py:1135  #, python-brace-format  msgid ""  "Homepage of Ishtar - if not defined a default homepage will appear. Use the "  "markdown syntax. {random_image} can be used to display a random image."  msgstr "" -#: models.py:1132 +#: models.py:1139  msgid "File external id"  msgstr "" -#: models.py:1134 +#: models.py:1141  msgid ""  "Formula to manage file external ID. Change this with care. With incorrect "  "formula, the application might be unusable and import of external data can "  "be destructive."  msgstr "" -#: models.py:1139 +#: models.py:1146  msgid "Parcel external id"  msgstr "" -#: models.py:1142 +#: models.py:1149  msgid ""  "Formula to manage parcel external ID. Change this with care. With incorrect "  "formula, the application might be unusable and import of external data can "  "be destructive."  msgstr "" -#: models.py:1147 +#: models.py:1154  msgid "Context record external id"  msgstr "" -#: models.py:1149 +#: models.py:1156  msgid ""  "Formula to manage context record external ID. Change this with care. With "  "incorrect formula, the application might be unusable and import of external "  "data can be destructive."  msgstr "" -#: models.py:1154 +#: models.py:1161  msgid "Base find external id"  msgstr "" -#: models.py:1156 +#: models.py:1163  msgid ""  "Formula to manage base find external ID. Change this with care. With "  "incorrect formula, the application might be unusable and import of external "  "data can be destructive."  msgstr "" -#: models.py:1161 +#: models.py:1168  msgid "Find external id"  msgstr "" -#: models.py:1163 +#: models.py:1170  msgid ""  "Formula to manage find external ID. Change this with care. With incorrect "  "formula, the application might be unusable and import of external data can "  "be destructive."  msgstr "" -#: models.py:1168 +#: models.py:1175  msgid "Container external id"  msgstr "" -#: models.py:1170 +#: models.py:1177  msgid ""  "Formula to manage container external ID. Change this with care. With "  "incorrect formula, the application might be unusable and import of external "  "data can be destructive."  msgstr "" -#: models.py:1175 +#: models.py:1182  msgid "Warehouse external id"  msgstr "" -#: models.py:1177 +#: models.py:1184  msgid ""  "Formula to manage warehouse external ID. Change this with care. With "  "incorrect formula, the application might be unusable and import of external "  "data can be destructive."  msgstr "" -#: models.py:1182 +#: models.py:1189  msgid "Raw name for person"  msgstr "" -#: models.py:1184 +#: models.py:1191  msgid ""  "Formula to manage person raw_name. Change this with care. With incorrect "  "formula, the application might be unusable and import of external data can "  "be destructive."  msgstr "" -#: models.py:1188 +#: models.py:1195  msgid "Current active"  msgstr "" -#: models.py:1189 +#: models.py:1196  msgid "Currency"  msgstr "" -#: models.py:1193 +#: models.py:1200  msgid "Ishtar site profile"  msgstr "" -#: models.py:1194 +#: models.py:1201  msgid "Ishtar site profiles"  msgstr "" -#: models.py:1263 +#: models.py:1270  msgid "Variable name"  msgstr "" -#: models.py:1264 +#: models.py:1271  msgid "Description of the variable"  msgstr "" -#: models.py:1266 models.py:2058 +#: models.py:1273 models.py:2067  msgid "Value"  msgstr "" -#: models.py:1269 +#: models.py:1276  msgid "Global variable"  msgstr "" -#: models.py:1379 models.py:1409 +#: models.py:1386 models.py:1416  msgid "Total"  msgstr "" -#: models.py:1386 models.py:1510 models.py:1522 +#: models.py:1393 models.py:1517 models.py:1529  #: templates/ishtar/sheet_person.html:22  #: templates/ishtar/dashboards/dashboard_main_detail.html:141  #: templates/ishtar/dashboards/dashboard_main_detail_users.html:26 @@ -828,750 +832,750 @@ msgstr ""  msgid "Number"  msgstr "" -#: models.py:1473 +#: models.py:1480  msgid "Administrative Act"  msgstr "" -#: models.py:1477 +#: models.py:1484  msgid "Associated object"  msgstr "" -#: models.py:1481 +#: models.py:1488  msgid "Document template"  msgstr "" -#: models.py:1482 +#: models.py:1489  msgid "Document templates"  msgstr "" -#: models.py:1513 models.py:1523 models.py:2278 +#: models.py:1520 models.py:1530 models.py:2287  msgid "State"  msgstr "" -#: models.py:1527 templates/blocks/JQueryAdvancedTown.html:12 +#: models.py:1534 templates/blocks/JQueryAdvancedTown.html:12  msgid "Department"  msgstr "" -#: models.py:1528 +#: models.py:1535  msgid "Departments"  msgstr "" -#: models.py:1565 +#: models.py:1572  msgid "Raw phone"  msgstr "" -#: models.py:1571 +#: models.py:1578  msgid "Alternative address is prefered"  msgstr "" -#: models.py:1610 +#: models.py:1617  msgid "Tel: "  msgstr "" -#: models.py:1614 +#: models.py:1621  msgid "Mobile: "  msgstr "" -#: models.py:1618 +#: models.py:1625  msgid "Email: "  msgstr "" -#: models.py:1623 +#: models.py:1630  msgid "Merge key"  msgstr "" -#: models.py:1697 +#: models.py:1704  msgid "Organization types"  msgstr "" -#: models.py:1743 +#: models.py:1750  msgid "Class name"  msgstr "" -#: models.py:1746 +#: models.py:1753  msgid "Importer - Model"  msgstr "" -#: models.py:1747 +#: models.py:1754  msgid "Importer - Models"  msgstr "" -#: models.py:1764 templates/ishtar/dashboards/dashboard_main.html:25 +#: models.py:1771 templates/ishtar/dashboards/dashboard_main.html:25  msgid "Users"  msgstr "" -#: models.py:1767 +#: models.py:1774  msgid "Associated model"  msgstr "" -#: models.py:1770 +#: models.py:1777  msgid "Models that can accept new items"  msgstr "" -#: models.py:1771 +#: models.py:1778  msgid "Leave blank for no restrictions"  msgstr "" -#: models.py:1773 +#: models.py:1780  msgid "Is template"  msgstr "" -#: models.py:1774 +#: models.py:1781  msgid "Unicity keys (separator \";\")"  msgstr "" -#: models.py:1778 +#: models.py:1785  msgid "Importer - Type"  msgstr "" -#: models.py:1779 +#: models.py:1786  msgid "Importer - Types"  msgstr "" -#: models.py:1872 +#: models.py:1881  msgid "Importer - Default"  msgstr "" -#: models.py:1873 +#: models.py:1882  msgid "Importer - Defaults"  msgstr "" -#: models.py:1908 +#: models.py:1917  msgid "Importer - Default value"  msgstr "" -#: models.py:1909 +#: models.py:1918  msgid "Importer - Default values"  msgstr "" -#: models.py:1942 +#: models.py:1951  msgid "Column number"  msgstr "" -#: models.py:1945 +#: models.py:1954  msgid "Required"  msgstr "" -#: models.py:1948 +#: models.py:1957  msgid "Importer - Column"  msgstr "" -#: models.py:1949 +#: models.py:1958  msgid "Importer - Columns"  msgstr "" -#: models.py:1969 +#: models.py:1978  msgid "Field name"  msgstr "" -#: models.py:1971 models.py:2005 +#: models.py:1980 models.py:2014  msgid "Force creation of new items"  msgstr "" -#: models.py:1973 models.py:2007 +#: models.py:1982 models.py:2016  msgid "Concatenate with existing"  msgstr "" -#: models.py:1975 models.py:2009 +#: models.py:1984 models.py:2018  msgid "Concatenate character"  msgstr "" -#: models.py:1979 +#: models.py:1988  msgid "Importer - Duplicate field"  msgstr "" -#: models.py:1980 +#: models.py:1989  msgid "Importer - Duplicate fields"  msgstr "" -#: models.py:1987 +#: models.py:1996  msgid "Regular expression"  msgstr "" -#: models.py:1990 +#: models.py:1999  msgid "Importer - Regular expression"  msgstr "" -#: models.py:1991 +#: models.py:2000  msgid "Importer - Regular expressions"  msgstr "" -#: models.py:2014 +#: models.py:2023  msgid "Importer - Target"  msgstr "" -#: models.py:2015 +#: models.py:2024  msgid "Importer - Targets"  msgstr "" -#: models.py:2039 views.py:545 +#: models.py:2048 views.py:549  msgid "True"  msgstr "" -#: models.py:2040 views.py:547 +#: models.py:2049 views.py:551  msgid "False"  msgstr "" -#: models.py:2059 +#: models.py:2068  msgid "Is set"  msgstr "" -#: models.py:2066 +#: models.py:2075  msgid "Importer - Target key"  msgstr "" -#: models.py:2067 +#: models.py:2076  msgid "Importer - Targets keys"  msgstr "" -#: models.py:2119 models.py:2877 +#: models.py:2128 models.py:2901  msgid "Format"  msgstr "" -#: models.py:2120 models.py:2969 +#: models.py:2129 models.py:2993  msgid "Operation type"  msgstr "" -#: models.py:2121 +#: models.py:2130  msgid "Period"  msgstr "" -#: models.py:2122 +#: models.py:2131  msgid "Report state"  msgstr "" -#: models.py:2123 +#: models.py:2132  msgid "Remain type"  msgstr "" -#: models.py:2124 +#: models.py:2133  msgid "Unit"  msgstr "" -#: models.py:2125 +#: models.py:2134  msgid "Activity type"  msgstr "" -#: models.py:2126 +#: models.py:2135  msgid "Material"  msgstr "" -#: models.py:2128 +#: models.py:2137  msgid "Conservatory state"  msgstr "" -#: models.py:2129 +#: models.py:2138  msgid "Container type"  msgstr "" -#: models.py:2130 +#: models.py:2139  msgid "Preservation type"  msgstr "" -#: models.py:2131 +#: models.py:2140  msgid "Object type"  msgstr "" -#: models.py:2132 +#: models.py:2141  msgid "Integrity type"  msgstr "" -#: models.py:2133 +#: models.py:2142  msgid "Remarkability type"  msgstr "" -#: models.py:2134 +#: models.py:2143  msgid "Batch type"  msgstr "" -#: models.py:2136 +#: models.py:2145  msgid "Identification type"  msgstr "" -#: models.py:2138 +#: models.py:2147  msgid "Context record relation type"  msgstr "" -#: models.py:2139 models.py:3027 +#: models.py:2148 models.py:3051  msgid "Spatial reference system"  msgstr "" -#: models.py:2140 models.py:2855 +#: models.py:2149 models.py:2879  msgid "Support type"  msgstr "" -#: models.py:2141 models.py:2520 +#: models.py:2150 models.py:2542  msgid "Title type"  msgstr "" -#: models.py:2147 +#: models.py:2156  msgid "Integer"  msgstr "" -#: models.py:2148 +#: models.py:2157  msgid "Float"  msgstr "" -#: models.py:2149 +#: models.py:2158  msgid "String"  msgstr "" -#: models.py:2150 templates/sheet_ope.html:86 +#: models.py:2159 templates/sheet_ope.html:86  msgid "Date"  msgstr "" -#: models.py:2152 templates/sheet_ope.html:61 templates/sheet_ope.html.py:83 +#: models.py:2161 templates/sheet_ope.html:61 templates/sheet_ope.html.py:83  #: templates/ishtar/dashboards/dashboard_main_detail.html:126  msgid "Year"  msgstr "" -#: models.py:2153 +#: models.py:2162  msgid "String to boolean"  msgstr "" -#: models.py:2154 +#: models.py:2163  msgctxt "filesystem"  msgid "File"  msgstr "" -#: models.py:2155 +#: models.py:2164  msgid "Unknow type"  msgstr "" -#: models.py:2171 +#: models.py:2180  msgid "4 digit year. e.g.: \"2015\""  msgstr "" -#: models.py:2172 +#: models.py:2181  msgid "4 digit year/month/day. e.g.: \"2015/02/04\""  msgstr "" -#: models.py:2173 +#: models.py:2182  msgid "Day/month/4 digit year. e.g.: \"04/02/2015\""  msgstr "" -#: models.py:2183 +#: models.py:2192  msgid "Options"  msgstr "" -#: models.py:2185 +#: models.py:2194  msgid "Split character(s)"  msgstr "" -#: models.py:2189 +#: models.py:2198  msgid "Importer - Formater type"  msgstr "" -#: models.py:2190 +#: models.py:2199  msgid "Importer - Formater types"  msgstr "" -#: models.py:2242 templates/ishtar/dashboards/dashboard_main_detail.html:63 +#: models.py:2251 templates/ishtar/dashboards/dashboard_main_detail.html:63  msgid "Created"  msgstr "" -#: models.py:2243 +#: models.py:2252  msgid "Analyse in progress"  msgstr "" -#: models.py:2244 +#: models.py:2253  msgid "Analysed"  msgstr "" -#: models.py:2245 +#: models.py:2254  msgid "Import pending"  msgstr "" -#: models.py:2246 +#: models.py:2255  msgid "Import in progress"  msgstr "" -#: models.py:2247 +#: models.py:2256  msgid "Finished with errors"  msgstr "" -#: models.py:2248 +#: models.py:2257  msgid "Finished"  msgstr "" -#: models.py:2249 +#: models.py:2258  msgid "Archived"  msgstr "" -#: models.py:2262 +#: models.py:2271  msgid "Imported file"  msgstr "" -#: models.py:2264 +#: models.py:2273  msgid "Associated images (zip file)"  msgstr "" -#: models.py:2266 +#: models.py:2275  msgid "Encoding"  msgstr "" -#: models.py:2268 +#: models.py:2277  msgid "Skip lines"  msgstr "" -#: models.py:2269 templates/ishtar/import_list.html:47 +#: models.py:2278 templates/ishtar/import_list.html:47  msgid "Error file"  msgstr "" -#: models.py:2272 +#: models.py:2281  msgid "Result file"  msgstr "" -#: models.py:2275 templates/ishtar/import_list.html:53 +#: models.py:2284 templates/ishtar/import_list.html:53  msgid "Match file"  msgstr "" -#: models.py:2281 +#: models.py:2290  msgid "Conservative import"  msgstr "" -#: models.py:2286 +#: models.py:2295  msgid "End date"  msgstr "" -#: models.py:2288 +#: models.py:2297  msgid "Remaining seconds"  msgstr "" -#: models.py:2293 +#: models.py:2302  msgid "Import"  msgstr "" -#: models.py:2310 +#: models.py:2332  msgid "Analyse"  msgstr "" -#: models.py:2312 models.py:2315 +#: models.py:2334 models.py:2337  msgid "Re-analyse"  msgstr "" -#: models.py:2313 +#: models.py:2335  msgid "Launch import"  msgstr "" -#: models.py:2316 +#: models.py:2338  msgid "Re-import"  msgstr "" -#: models.py:2317 +#: models.py:2339  msgid "Archive"  msgstr "" -#: models.py:2319 +#: models.py:2341  msgid "Unarchive"  msgstr "" -#: models.py:2320 widgets.py:130 templates/ishtar/form_delete.html:11 +#: models.py:2342 widgets.py:130 templates/ishtar/form_delete.html:11  msgid "Delete"  msgstr "" -#: models.py:2461 +#: models.py:2483  msgid "Organizations"  msgstr "" -#: models.py:2463 +#: models.py:2485  msgid "Can view all Organizations"  msgstr "" -#: models.py:2464 +#: models.py:2486  msgid "Can view own Organization"  msgstr "" -#: models.py:2465 +#: models.py:2487  msgid "Can add own Organization"  msgstr "" -#: models.py:2467 +#: models.py:2489  msgid "Can change own Organization"  msgstr "" -#: models.py:2469 +#: models.py:2491  msgid "Can delete own Organization"  msgstr "" -#: models.py:2504 +#: models.py:2526  msgid "Groups"  msgstr "" -#: models.py:2509 +#: models.py:2531  msgid "Person types"  msgstr "" -#: models.py:2521 +#: models.py:2543  msgid "Title types"  msgstr "" -#: models.py:2530 +#: models.py:2552  msgid "Mr"  msgstr "" -#: models.py:2531 +#: models.py:2553  msgid "Miss"  msgstr "" -#: models.py:2532 +#: models.py:2554  msgid "Mr and Mrs"  msgstr "" -#: models.py:2533 +#: models.py:2555  msgid "Mrs"  msgstr "" -#: models.py:2534 +#: models.py:2556  msgid "Doctor"  msgstr "" -#: models.py:2567 +#: models.py:2589  msgid "Contact type"  msgstr "" -#: models.py:2570 models.py:2634 +#: models.py:2592 models.py:2656  msgid "Types"  msgstr "" -#: models.py:2573 +#: models.py:2595  msgid "Is attached to"  msgstr "" -#: models.py:2578 +#: models.py:2600  msgid "Persons"  msgstr "" -#: models.py:2580 +#: models.py:2602  msgid "Can view all Persons"  msgstr "" -#: models.py:2581 +#: models.py:2603  msgid "Can view own Person"  msgstr "" -#: models.py:2582 +#: models.py:2604  msgid "Can add own Person"  msgstr "" -#: models.py:2583 +#: models.py:2605  msgid "Can change own Person"  msgstr "" -#: models.py:2584 +#: models.py:2606  msgid "Can delete own Person"  msgstr "" -#: models.py:2762 +#: models.py:2784  msgid "Advanced shortcut menu"  msgstr "" -#: models.py:2765 +#: models.py:2787  msgid "Ishtar user"  msgstr "" -#: models.py:2766 +#: models.py:2788  msgid "Ishtar users"  msgstr "" -#: models.py:2808 +#: models.py:2832  msgid "To modify the password use the form in Auth > User"  msgstr "" -#: models.py:2814 +#: models.py:2838  msgid "Author types"  msgstr "" -#: models.py:2847 +#: models.py:2871  msgid "Source types"  msgstr "" -#: models.py:2856 +#: models.py:2880  msgid "Support types"  msgstr "" -#: models.py:2863 +#: models.py:2887  msgid "Format type"  msgstr "" -#: models.py:2864 +#: models.py:2888  msgid "Format types"  msgstr "" -#: models.py:2872 +#: models.py:2896  msgid "External ID"  msgstr "" -#: models.py:2875 +#: models.py:2899  msgid "Support"  msgstr "" -#: models.py:2879 +#: models.py:2903  msgid "Scale"  msgstr "" -#: models.py:2893 +#: models.py:2917  msgid "Item number"  msgstr "" -#: models.py:2894 +#: models.py:2918  msgid "Ref."  msgstr "" -#: models.py:2897 +#: models.py:2921  msgid "Internal ref."  msgstr "" -#: models.py:2940 +#: models.py:2964  msgid "Surface (m2)"  msgstr "" -#: models.py:2941 templates/sheet_ope.html:46 templates/sheet_ope.html.py:107 +#: models.py:2965 templates/sheet_ope.html:46 templates/sheet_ope.html.py:107  msgid "Localisation"  msgstr "" -#: models.py:2966 +#: models.py:2990  msgid "Is preventive"  msgstr "" -#: models.py:2970 +#: models.py:2994  msgid "Operation types"  msgstr "" -#: models.py:2999 +#: models.py:3023  msgid "Preventive"  msgstr "" -#: models.py:3000 +#: models.py:3024  msgid "Research"  msgstr "" -#: models.py:3023 +#: models.py:3047  msgid "Authority name"  msgstr "" -#: models.py:3024 +#: models.py:3048  msgid "Authority SRID"  msgstr "" -#: models.py:3028 +#: models.py:3052  msgid "Spatial reference systems"  msgstr "" -#: utils.py:84 +#: utils.py:100  msgid " (...)"  msgstr "" -#: utils.py:130 +#: utils.py:146  msgid "Load another random image?"  msgstr "" -#: views.py:118 +#: views.py:119  msgid "New person"  msgstr "" -#: views.py:126 +#: views.py:127  msgid "Person modification"  msgstr "" -#: views.py:141 +#: views.py:142  msgid "Person deletion"  msgstr "" -#: views.py:152 +#: views.py:153  msgid "New organization"  msgstr "" -#: views.py:159 +#: views.py:160  msgid "Organization modification"  msgstr "" -#: views.py:175 +#: views.py:176  msgid "Organization deletion"  msgstr "" -#: views.py:182 +#: views.py:183  msgid "Account management"  msgstr "" -#: views.py:188 +#: views.py:189  msgid "Account deletion"  msgstr "" -#: views.py:240 +#: views.py:241  msgid "Archaeological file"  msgstr "" -#: views.py:241 +#: views.py:242  msgid "Operation"  msgstr "" -#: views.py:243 +#: views.py:244  msgid "Context record"  msgstr "" -#: views.py:245 +#: views.py:246  msgid "Find"  msgstr "" -#: views.py:247 +#: views.py:248  msgid "Treatment request"  msgstr "" -#: views.py:248 +#: views.py:249  msgid "Treatment"  msgstr "" -#: views.py:1304 views.py:1347 +#: views.py:1329 views.py:1372  msgid "Operation not permitted."  msgstr "" -#: views.py:1306 +#: views.py:1331  #, python-format  msgid "New %s"  msgstr "" -#: views.py:1365 views.py:1415 +#: views.py:1390 views.py:1440  msgid "Archaeological files"  msgstr "" -#: views.py:1366 views.py:1419 +#: views.py:1391 views.py:1444  msgid "Operations"  msgstr "" -#: views.py:1368 views.py:1423 +#: views.py:1393 views.py:1448  msgid "Context records"  msgstr "" -#: views.py:1370 views.py:1426 +#: views.py:1395 views.py:1451  msgid "Finds"  msgstr "" -#: views.py:1619 templates/ishtar/import_list.html:43 +#: views.py:1644 templates/ishtar/import_list.html:43  msgid "Link unmatched items"  msgstr "" -#: views.py:1634 +#: views.py:1659  msgid "Delete import"  msgstr "" -#: views.py:1673 +#: views.py:1698  msgid "Merge persons"  msgstr "" -#: views.py:1697 +#: views.py:1722  msgid "Select the main person"  msgstr "" -#: views.py:1706 +#: views.py:1731  msgid "Merge organization"  msgstr "" -#: views.py:1716 +#: views.py:1741  msgid "Select the main organization"  msgstr "" -#: views.py:1756 views.py:1772 +#: views.py:1781 views.py:1797  msgid "Corporation manager"  msgstr "" @@ -1591,15 +1595,15 @@ msgstr ""  msgid "Remove"  msgstr "" -#: wizards.py:343 templates/ishtar/import_delete.html:20 +#: wizards.py:344 templates/ishtar/import_delete.html:20  msgid "Yes"  msgstr "" -#: wizards.py:345 +#: wizards.py:346  msgid "No"  msgstr "" -#: wizards.py:1338 +#: wizards.py:1362  #, python-format  msgid "[%(app_name)s] Account creation/modification"  msgstr "" @@ -1962,7 +1966,7 @@ msgstr ""  msgid "where the magic happens."  msgstr "" -#: templates/window.html:40 templates/blocks/JQueryJqGrid.html:28 +#: templates/window.html:40 templates/blocks/JQueryJqGrid.html:34  #: templates/ishtar/manage_basket.html:12  msgid "Add"  msgstr "" @@ -1984,32 +1988,36 @@ msgstr ""  msgid "Search and select an item"  msgstr "" -#: templates/blocks/JQueryJqGrid.html:17 templates/blocks/JQueryJqGrid.html:23 +#: templates/blocks/JQueryJqGrid.html:13 +msgid "Pinned search:" +msgstr "" + +#: templates/blocks/JQueryJqGrid.html:23 templates/blocks/JQueryJqGrid.html:29  #: templates/ishtar/blocks/window_tables/dynamic_documents.html:9  #: templates/ishtar/blocks/window_tables/dynamic_documents.html:12  msgid "Export as CSV"  msgstr "" -#: templates/blocks/JQueryJqGrid.html:17 templates/blocks/JQueryJqGrid.html:23 +#: templates/blocks/JQueryJqGrid.html:23 templates/blocks/JQueryJqGrid.html:29  #: templates/ishtar/blocks/window_tables/dynamic_documents.html:9  msgid "CSV"  msgstr "" -#: templates/blocks/JQueryJqGrid.html:18 +#: templates/blocks/JQueryJqGrid.html:24  #: templates/ishtar/blocks/window_tables/dynamic_documents.html:10  msgid "Export as CSV - full"  msgstr "" -#: templates/blocks/JQueryJqGrid.html:18 +#: templates/blocks/JQueryJqGrid.html:24  #: templates/ishtar/blocks/window_tables/dynamic_documents.html:10  msgid "CSV full"  msgstr "" -#: templates/blocks/JQueryJqGrid.html:20 +#: templates/blocks/JQueryJqGrid.html:26  msgid "Export as CSV - "  msgstr "" -#: templates/blocks/JQueryJqGrid.html:99 +#: templates/blocks/JQueryJqGrid.html:105  #: templates/ishtar/blocks/window_tables/dynamic_documents.html:41  msgid "An error as occured during search. Check your query fields."  msgstr "" diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 2496e4372..24704dd21 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -489,8 +489,11 @@ class GeneralType(Cached, models.Model):      @classmethod      def get_types(cls, dct={}, instances=False, exclude=[], empty_first=True,                    default=None, initial=None, force=False): -        types = cls._pre_get_types(dct, instances, exclude, empty_first, -                                   default, force) +        types = [] +        if not instances and empty_first and not default: +            types = [('', '--')] +        types += cls._pre_get_types(dct, instances, exclude, +                                    default, force)          if not initial:              return types          new_vals = cls._get_initial_types(initial, [idx for idx, lbl in types]) @@ -499,13 +502,13 @@ class GeneralType(Cached, models.Model):      @classmethod      def _pre_get_types(cls, dct={}, instances=False, exclude=[], -                       empty_first=True, default=None, force=False): +                       default=None, force=False):          # cache          cache_key = None          if not instances:              keys = ['__get_types'] -            keys += [u"{}".format(ex) for ex in exclude] + [ -                empty_first and 'empty_first' or ''] + [u"{}".format(default)] +            keys += [u"{}".format(ex) for ex in exclude] + \ +                [u"{}".format(default)]              keys += [u'{}-{}'.format(unicode(k), dct[k]) for k in dct]              cache_key, value = get_cache(cls, keys)              if value and not force: @@ -515,28 +518,25 @@ class GeneralType(Cached, models.Model):              if not cache_key:                  return cls._get_parent_types(                      base_dct, instances, exclude=exclude, -                    empty_first=empty_first, default=default) +                    default=default)              vals = [v for v in cls._get_parent_types(                      base_dct, instances, exclude=exclude, -                    empty_first=empty_first, default=default)] +                    default=default)]              cache.set(cache_key, vals, settings.CACHE_TIMEOUT)              return vals          if not cache_key:              return cls._get_types(base_dct, instances, exclude=exclude, -                                  empty_first=empty_first, default=default) +                                  default=default)          vals = [v for v in cls._get_types( -            base_dct, instances, exclude=exclude, empty_first=empty_first, +            base_dct, instances, exclude=exclude,              default=default)]          cache.set(cache_key, vals, settings.CACHE_TIMEOUT)          return vals      @classmethod -    def _get_types(cls, dct={}, instances=False, exclude=[], empty_first=True, -                   default=None): +    def _get_types(cls, dct={}, instances=False, exclude=[], default=None):          dct['available'] = True -        if not instances and empty_first and not default: -            yield ('', '--')          if default:              try:                  default = cls.objects.get(txt_idx=default) @@ -606,10 +606,8 @@ class GeneralType(Cached, models.Model):      @classmethod      def _get_parent_types(cls, dct={}, instances=False, exclude=[], -                          empty_first=True, default=None): +                          default=None):          dct['available'] = True -        if not instances and empty_first: -            yield ('', '--')          dct['parent'] = None          items = cls.objects.filter(**dct)          if exclude: diff --git a/ishtar_common/templates/blocks/JQueryJqGrid.html b/ishtar_common/templates/blocks/JQueryJqGrid.html index 607f81f7d..258082877 100644 --- a/ishtar_common/templates/blocks/JQueryJqGrid.html +++ b/ishtar_common/templates/blocks/JQueryJqGrid.html @@ -8,6 +8,12 @@  <h4>{% trans "Search and select an item" %}</h4> +<h5 id="pinned_search_{{name}}"> +    <i class="fa fa-thumb-tack"></i>   +    <strong>{% trans "Pinned search:" %}</strong> +    <em><span id="pinned_search_content_{{name}}"></span></em> +</h5> +  <table id='grid_{{name}}' class='jqgrid'></table>  <div id='pager_{{name}}'></div> @@ -97,6 +103,19 @@ jQuery(document).ready(function(){      jsonReader : {repeatitems: false},      loadError: function (jqXHR, textStatus, errorThrown) {          alert("{% trans "An error as occured during search. Check your query fields." %}"); +    }, +    beforeProcessing: function(data, status, xhr){ +        $('#pinned_search_content_{{name}}').html(''); +        for (idx in data){ +            if (idx == 'pinned-search' && data[idx] != ''){ +               $('#pinned_search_content_{{name}}').html(data[idx]); +            } +        } +        if ($('#pinned_search_content_{{name}}').html()){ +            $('#pinned_search_{{name}}').show(); +        } else { +            $('#pinned_search_{{name}}').hide(); +        }      }    });  {% if multiple %} diff --git a/ishtar_common/templates/ishtar/blocks/advanced_shortcut_menu.html b/ishtar_common/templates/ishtar/blocks/advanced_shortcut_menu.html index 2cf80da06..1758bcf54 100644 --- a/ishtar_common/templates/ishtar/blocks/advanced_shortcut_menu.html +++ b/ishtar_common/templates/ishtar/blocks/advanced_shortcut_menu.html @@ -13,7 +13,7 @@  </span>  <div class="short-menu-buttons btn-group" role="group">    <button type="button" class="btn" id='short-menu-simple' title="{% trans 'Simple menu limited to your own items. Be careful only the last 100 items are displayed.' %}">{% trans "simple" %}</button> -  <button type="button" class="btn btn-selected" id='short-menu-advanced' title="{% trans 'Advanced menu.' %}">{% trans "advanced" %}</button> +  <button type="button" class="btn btn-selected" id='short-menu-advanced' title="{% trans 'Advanced menu' %}">{% trans "advanced" %}</button>  </div>  <div id='action_current_items'>  <p><i class="icon fa fa-thumb-tack fa-2x" aria-hidden="true" title="{% trans 'Pin an item in order to constrain default searches with this item. By default only your items are displayed. New created and modified items are auto-pin.' %}"></i></p> diff --git a/ishtar_common/templates/ishtar/blocks/shortcut_menu.html b/ishtar_common/templates/ishtar/blocks/shortcut_menu.html index 05aaed6d8..5973eba3f 100644 --- a/ishtar_common/templates/ishtar/blocks/shortcut_menu.html +++ b/ishtar_common/templates/ishtar/blocks/shortcut_menu.html @@ -13,7 +13,7 @@  </span>  <div class="short-menu-buttons btn-group" role="group">    <button type="button" class="btn btn-selected" id='short-menu-simple' title="{% trans 'Simple menu limited to your own items. Be careful only the last 100 items are displayed.' %}">{% trans "simple" %}</button> -  <button type="button" class="btn" id='short-menu-advanced' title="{% trans 'Advanced menu.' %}">{% trans "advanced" %}</button> +  <button type="button" class="btn" id='short-menu-advanced' title="{% trans 'Advanced menu' %}">{% trans "advanced" %}</button>  </div>  <div>  <i class="icon fa fa-thumb-tack fa-2x" aria-hidden="true" title="{% trans 'Pin an item in order to constrain default searches with this item. By default only your items are displayed. New created and modified items are auto-pin.' %}"></i> diff --git a/ishtar_common/templates/ishtar/wizard/validation_bar.html b/ishtar_common/templates/ishtar/wizard/validation_bar.html index 09907af67..a1590858f 100644 --- a/ishtar_common/templates/ishtar/wizard/validation_bar.html +++ b/ishtar_common/templates/ishtar/wizard/validation_bar.html @@ -1,7 +1,9 @@  {% load i18n %}  {% load url from future %}  <div id='validation-bar'> -  <input type="submit" id="submit_form" name='validate' value="{% trans "Validate" %}"/> -  {% if next_steps %}<input type="submit" id="submit_end_form" name='validate_and_end' value="{% trans "Validate and end" %}"/>{% endif %} -  <a href='{% url 'reset_wizards' %}' id="reset_wizards" class='button'>{% trans "Cancel" %}</a> +    <input type="submit" id="submit_form" name='validate' value="{% trans 'Validate' %}"/> +    {% if last_step_is_available and next_steps %} +    <input type="submit" id="submit_end_form" name='validate_and_end' value="{% trans 'Validate and end' %}"/> +    {% endif %} +    <a href="{% url 'reset_wizards' %}" id="reset_wizards" class='button'>{% trans "Cancel" %}</a>  </div> diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py index 42bb1860e..a9e92e1f2 100644 --- a/ishtar_common/tests.py +++ b/ishtar_common/tests.py @@ -30,8 +30,9 @@ from django.core.files.base import File as DjangoFile  from django.core.files.uploadedfile import SimpleUploadedFile  from django.core.management import call_command  from django.core.urlresolvers import reverse +from django.db import connection, transaction  from django.template.defaultfilters import slugify -from django.test import TestCase +from django.test import TestCase as BaseTestCase  from django.test.client import Client  from django.test.simple import DjangoTestSuiteRunner @@ -39,6 +40,9 @@ from ishtar_common import models  from ishtar_common import forms_common  from ishtar_common.utils import post_save_point +from archaeological_context_records.models import CRBulkView +from archaeological_finds.models import BFBulkView, FBulkView, FirstBaseFindView +  """  from django.conf import settings  import tempfile, datetime @@ -82,6 +86,17 @@ def create_user():      return username, password, user +class TestCase(BaseTestCase): +    def _pre_setup(self): +        super(TestCase, self)._pre_setup() +        if settings.USE_SPATIALITE_FOR_TESTS: +            return +        c = connection.cursor() +        for view in [CRBulkView, FirstBaseFindView, BFBulkView, FBulkView]: +            c.execute(view.CREATE_SQL) +            transaction.commit_unless_managed() + +  class CommandsTestCase(TestCase):      def test_clean_ishtar(self):          """ @@ -102,20 +117,30 @@ class WizardTestFormData(object):      """      Test set to simulate wizard steps      """ -    def __init__(self, name, form_datas, ignored=[], extra_tests=[]): +    def __init__(self, name, form_datas, ignored=[], pre_tests=[], +                 extra_tests=[]):          """          :param name: explicit name of the test          :param form_datas: dict with data for each step - dict key are wizard          step name          :param ignored: steps to be ignored in wizard processing +        :param pre_tests: list of function to be executed before the wizard          :param extra_tests: list of extra tests. Theses tests must be functions          accepting two parameters: the current test object and the final step          response          """          self.form_datas = form_datas          self.ignored = ignored[:] +        self.pre_tests = pre_tests          self.extra_tests = extra_tests +    def inits(self, test_object): +        """ +        Initialisations before the wizard. +        """ +        for pre in self.pre_tests: +            pre(test_object) +      def tests(self, test_object, final_step_response):          """          Specific tests for theses datas. Raise Exception if not OK. @@ -185,6 +210,7 @@ class WizardTest(object):          url = reverse(self.url_name)          self.pre_wizard()          for test_form_data in self.form_datas: +            test_form_data.inits(self)              form_data = test_form_data.form_datas              ignored = test_form_data.ignored              for idx, step in enumerate(self.steps): @@ -207,27 +233,27 @@ class WizardTest(object):                          for k in d:                              data['{}-{}'.format(current_step, k)] = d[k] -                next_idx, next_form = idx + 1, None -                while len(self.steps) > next_idx: -                    if self.steps[idx + 1][0] not in ignored: -                        next_form = self.steps[idx + 1][0] -                        break -                    next_idx += 1 -                if next_form: -                    try: -                        response = self.client.post(url, data) -                    except ValidationError as e: -                        # on ManagementForm data is missing or has been tampered -                        # error verify the wizard_name or step name -                        raise ValidationError(u"Errors: {} on {}.".format( -                            u" - ".join(e.messages), current_step)) -                    self.check_response(response, current_step) +                next_form_is_checked = len(self.steps) > idx + 1 and \ +                    self.steps[idx + 1][0] not in ignored +                try: +                    response = self.client.post(url, data, +                                                follow=not next_form_is_checked) +                except ValidationError as e: +                    # on ManagementForm data is missing or has been tampered +                    # error verify the wizard_name or step name +                    raise ValidationError(u"Errors: {} on {}.".format( +                        u" - ".join(e.messages), current_step)) +                self.check_response(response, current_step) +                if next_form_is_checked: +                    next_form = self.steps[idx + 1][0]                      self.assertRedirects(                          response,                          '/{}/{}'.format(self.url_name, next_form)) -                else: -                    response = self.client.post(url, data, follow=True) -                    self.check_response(response, current_step) +                if idx == len(self.steps) - 1: +                    #  last form +                    self.assertRedirects( +                        response, +                        '/{}/done'.format(self.url_name))              test_form_data.tests(self, response)          self.post_wizard() diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index 83534d93a..f1e2e4b96 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -55,10 +55,21 @@ def get_cache(cls, extra_args=[]):      return cache_key, cache.get(cache_key) +def force_cached_label_changed(sender, **kwargs): +    if not kwargs.get('instance'): +        return +    kwargs['instance']._cached_label_checked = False +    cached_label_changed(sender, **kwargs) + +  def cached_label_changed(sender, **kwargs):      if not kwargs.get('instance'):          return      instance = kwargs.get('instance') + +    if hasattr(instance, 'test_obj'): +        instance.test_obj.reached(sender, **kwargs) +      if hasattr(instance, '_cached_label_checked') \              and instance._cached_label_checked:          return @@ -76,15 +87,22 @@ def cached_label_changed(sender, **kwargs):          if hasattr(instance, '_cascade_change') and instance._cascade_change:              instance.skip_history_when_saving = True          instance.save() -    if hasattr(instance, '_get_associated_cached_labels'): +    updated = False +    if hasattr(instance, '_cached_labels_bulk_update'): +        updated = instance._cached_labels_bulk_update() +    if not updated and hasattr(instance, '_get_associated_cached_labels'):          for item in instance._get_associated_cached_labels():              item._cascade_change = True +            if hasattr(instance, 'test_obj'): +                item.test_obj = instance.test_obj              cached_label_changed(item.__class__, instance=item)  SHORTIFY_STR = ugettext(" (...)")  def shortify(lbl, number=20): +    if not lbl: +        lbl = ''      if len(lbl) <= number:          return lbl      return lbl[:number - len(SHORTIFY_STR)] + SHORTIFY_STR diff --git a/ishtar_common/views.py b/ishtar_common/views.py index c9eb9fec8..a4ad130be 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -58,7 +58,8 @@ from menus import menu  from archaeological_files.models import File  from archaeological_operations.models import Operation  from archaeological_context_records.models import ContextRecord -from archaeological_finds.models import Find, Treatment, TreatmentFile +from archaeological_finds.models import Find, Treatment, TreatmentFile, \ +    FindBasket  from archaeological_operations.forms import DashboardForm as DashboardFormOpe  from archaeological_files.forms import DashboardForm as DashboardFormFile @@ -307,15 +308,18 @@ def shortcut_menu(request):      return render_to_response('ishtar/blocks/shortcut_menu.html', dct,                                context_instance=RequestContext(request)) +CURRENT_ITEM_KEYS = (('file', File), +                     ('operation', Operation), +                     ('contextrecord', ContextRecord), +                     ('find', Find), +                     ('treatmentfile', TreatmentFile), +                     ('treatment', Treatment)) +CURRENT_ITEM_KEYS_DICT = dict(CURRENT_ITEM_KEYS) +  def get_current_items(request):      currents = {} -    for key, model in (('file', File), -                       ('operation', Operation), -                       ('contextrecord', ContextRecord), -                       ('find', Find), -                       ('treatmentfile', TreatmentFile), -                       ('treatment', Treatment)): +    for key, model in CURRENT_ITEM_KEYS:          currents[key] = None          if key in request.session and request.session[key]:              try: @@ -693,6 +697,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                  q = Q(**{req_key: val})                  reqs |= q              and_reqs.append(reqs) +        pinned_search = ""          if 'submited' not in request_items and full != 'shortcut':              # default search              # an item is selected in the default menu @@ -700,17 +705,36 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                 request.session[default_name]:                  value = request.session[default_name]                  if 'basket-' in value: -                    dct = {"basket__pk": -                           request.session[default_name].split('-')[-1]} +                    try: +                        dct = {"basket__pk": +                               request.session[default_name].split('-')[-1]} +                        pinned_search = unicode(FindBasket.objects.get( +                            pk=dct["basket__pk"])) +                    except FindBasket.DoesNotExist: +                        pass                  else: -                    dct = {"pk": request.session[default_name]} +                    try: +                        dct = {"pk": request.session[default_name]} +                        pinned_search = unicode(model._meta.verbose_name)\ +                            + u" - " +  unicode( +                                model.objects.get(pk=dct["pk"])) +                    except model.DoesNotExist: +                        pass              elif dct == (base_request or {}):                  # a parent item may be selected in the default menu                  for name, key in my_relative_session_names:                      if name in request.session and request.session[name] \ -                            and 'basket-' not in request.session[name]: -                        dct.update({key: request.session[name]}) -                        break +                            and 'basket-' not in request.session[name] \ +                            and name in CURRENT_ITEM_KEYS_DICT: +                        up_model = CURRENT_ITEM_KEYS_DICT[name] +                        try: +                            dct.update({key: request.session[name]}) +                            pinned_search = unicode(up_model._meta.verbose_name)\ +                                + u" - " + unicode( +                                    up_model.objects.get(pk=dct[key])) +                            break +                        except up_model.DoesNotExist: +                            pass              if (not dct or data_type == 'csv') \                      and func_name in request.session:                  dct = request.session[func_name] @@ -1053,6 +1077,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                  data = json.dumps({                      "records": items_nb,                      "rows": rows, +                    "pinned-search": pinned_search,                      "page": page_nb,                      "total": (items_nb / row_nb + 1) if row_nb else items_nb,                  }) diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index 5c4e1d3f9..874b68eae 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -238,42 +238,70 @@ class Wizard(NamedUrlWizardView):                          'previous_step_counter': previous_step_counter})          storage = self.storage          # if modification: show the next steps -        if self.modification: -            next_step = self.steps.first -            current_step_passed = False -            # force rechecking of conditions -            self.get_form_list() -            while next_step: -                # check if the form is initialized otherwise initialize it -                if not storage.get_step_data(next_step): -                    values = self.get_form_initial(next_step) -                    prefixed_values = MultiValueDict() -                    if not isinstance(values, list): -                        for key in values: -                            form_key = next_step + '-' + key -                            if isinstance(values, MultiValueDict): -                                prefixed_values.setlist(form_key, -                                                        values.getlist(key)) -                            else: -                                prefixed_values[form_key] = values[key] +        # if self.modification or True: +        next_step = self.steps.first +        current_step_passed, no_next = False, False +        # force rechecking of conditions +        self.get_form_list() +        last_step_is_available = True +        while next_step: +            # check if the form is initialized otherwise initialize it +            if self.modification and not storage.get_step_data(next_step): +                values = self.get_form_initial(next_step) +                prefixed_values = MultiValueDict() +                if not isinstance(values, list): +                    for key in values: +                        form_key = next_step + '-' + key +                        if isinstance(values, MultiValueDict): +                            prefixed_values.setlist(form_key, +                                                    values.getlist(key)) +                        else: +                            prefixed_values[form_key] = values[key] +                else: +                    for formset_idx, v in enumerate(values): +                        prefix = u"-%d-" % formset_idx +                        for key in v: +                            form_key = next_step + prefix + key +                            prefixed_values[form_key] = v[key] +                if not prefixed_values and \ +                        next_step not in self.get_ignore_init_steps(): +                    # simulate a non empty data for form that might be +                    # valid when empty +                    prefixed_values['__non_empty_data'] = '' +                storage.set_step_data(next_step, prefixed_values) +            if step == next_step: +                current_step_passed = True +            elif current_step_passed: +                next_steps.append(self.form_list[next_step].form_label) + +            # creation +            if not self.modification: +                form_obj = self.get_form(step=next_step) +                if current_step_passed: +                    initialise_data = False +                    # formsets are considered not required +                    if hasattr(form_obj, 'fields'): +                        # display next step until a required field is met +                        if [field_key for field_key in form_obj.fields +                                if form_obj.fields[field_key].required]: +                            no_next = True +                        elif next_step not in self.get_ignore_init_steps(): +                            initialise_data = True                      else: -                        for formset_idx, v in enumerate(values): -                            prefix = u"-%d-" % formset_idx -                            for key in v: -                                form_key = next_step + prefix + key -                                prefixed_values[form_key] = v[key] -                    if not prefixed_values and \ -                            next_step not in self.get_ignore_init_steps(): +                        initialise_data = True +                    if initialise_data:                          # simulate a non empty data for form that might be                          # valid when empty +                        prefixed_values = MultiValueDict()                          prefixed_values['__non_empty_data'] = '' -                    storage.set_step_data(next_step, prefixed_values) -                if step == next_step: -                    current_step_passed = True -                elif current_step_passed: -                    next_steps.append(self.form_list[next_step].form_label) -                next_step = self.get_next_step(next_step) -        context.update({'next_steps': next_steps}) +                        storage.set_step_data(next_step, prefixed_values) + +            next_step = self.get_next_step(next_step) +            if no_next: +                last_step_is_available = False +                break +        context.update({'next_steps': next_steps, +                        'last_step_is_available': last_step_is_available})          # not last step: validation          if current_step != self.steps.last:              return context | 
