mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-04 03:27:12 -05:00 
			
		
		
		
	Feature: scheduled workflow trigger (#8036)
This commit is contained in:
		
							parent
							
								
									d5572137de
								
							
						
					
					
						commit
						2b29233a1e
					
				
							
								
								
									
										2
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							@ -1,7 +1,7 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "_meta": {
 | 
					    "_meta": {
 | 
				
			||||||
        "hash": {
 | 
					        "hash": {
 | 
				
			||||||
            "sha256": "e4cb2328c49829f56793ef25780dcc73ea8e4838e6e9bc25d1b6feb74eb3befe"
 | 
					            "sha256": "584249cbeaf29659c975000b5e02b12e45d768d795e4a8ac36118e73bd7c0b8a"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "pipfile-spec": 6,
 | 
					        "pipfile-spec": 6,
 | 
				
			||||||
        "requires": {},
 | 
					        "requires": {},
 | 
				
			||||||
 | 
				
			|||||||
@ -331,8 +331,10 @@ Currently, there are three events that correspond to workflow trigger 'types':
 | 
				
			|||||||
   be used for filtering.
 | 
					   be used for filtering.
 | 
				
			||||||
3. **Document Updated**: when a document is updated. Similar to 'added' events, triggers can include filtering by content matching,
 | 
					3. **Document Updated**: when a document is updated. Similar to 'added' events, triggers can include filtering by content matching,
 | 
				
			||||||
   tags, doc type, or correspondent.
 | 
					   tags, doc type, or correspondent.
 | 
				
			||||||
 | 
					4. **Scheduled**: a scheduled trigger that can be used to run workflows at a specific time. The date used can be either the document
 | 
				
			||||||
 | 
					   added, created, updated date or you can specify a (date) custom field. You can also specify a day offset from the date.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The following flow diagram illustrates the three trigger types:
 | 
					The following flow diagram illustrates the three document trigger types:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```mermaid
 | 
					```mermaid
 | 
				
			||||||
flowchart TD
 | 
					flowchart TD
 | 
				
			||||||
 | 
				
			|||||||
@ -1213,19 +1213,19 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">174</context>
 | 
					          <context context-type="linenumber">200</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">193</context>
 | 
					          <context context-type="linenumber">219</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">260</context>
 | 
					          <context context-type="linenumber">286</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">279</context>
 | 
					          <context context-type="linenumber">305</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
 | 
				
			||||||
@ -1248,19 +1248,19 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">182</context>
 | 
					          <context context-type="linenumber">208</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">201</context>
 | 
					          <context context-type="linenumber">227</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">268</context>
 | 
					          <context context-type="linenumber">294</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">287</context>
 | 
					          <context context-type="linenumber">313</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
 | 
				
			||||||
@ -1286,11 +1286,11 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">207</context>
 | 
					          <context context-type="linenumber">233</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">293</context>
 | 
					          <context context-type="linenumber">319</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
 | 
				
			||||||
@ -1991,6 +1991,10 @@
 | 
				
			|||||||
          <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">11</context>
 | 
					          <context context-type="linenumber">11</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">59</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">239</context>
 | 
					          <context context-type="linenumber">239</context>
 | 
				
			||||||
@ -3482,6 +3486,10 @@
 | 
				
			|||||||
          <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">74</context>
 | 
					          <context context-type="linenumber">74</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">55</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">248</context>
 | 
					          <context context-type="linenumber">248</context>
 | 
				
			||||||
@ -3581,7 +3589,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">137</context>
 | 
					          <context context-type="linenumber">163</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6457471243969293847" datatype="html">
 | 
					      <trans-unit id="6457471243969293847" datatype="html">
 | 
				
			||||||
@ -3998,7 +4006,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">162</context>
 | 
					          <context context-type="linenumber">188</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="4754802869258527587" datatype="html">
 | 
					      <trans-unit id="4754802869258527587" datatype="html">
 | 
				
			||||||
@ -4016,7 +4024,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">163</context>
 | 
					          <context context-type="linenumber">189</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1519954996184640001" datatype="html">
 | 
					      <trans-unit id="1519954996184640001" datatype="html">
 | 
				
			||||||
@ -4462,322 +4470,417 @@
 | 
				
			|||||||
          <context context-type="linenumber">121</context>
 | 
					          <context context-type="linenumber">121</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="5337452276818111131" datatype="html">
 | 
				
			||||||
 | 
					        <source>Set scheduled trigger offset and which field to use.</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">123</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="4779176004576564638" datatype="html">
 | 
				
			||||||
 | 
					        <source>Offset days</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">126</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="8816141193078203810" datatype="html">
 | 
				
			||||||
 | 
					        <source>Use 0 for immediate.</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">126</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="3726450101884717309" datatype="html">
 | 
				
			||||||
 | 
					        <source>Relative to</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">129</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="1500318445250299453" datatype="html">
 | 
				
			||||||
 | 
					        <source>Delay custom field</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">133</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="1088170562604583291" datatype="html">
 | 
				
			||||||
 | 
					        <source>Custom field to use for date.</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">133</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="1011433830042635014" datatype="html">
 | 
				
			||||||
 | 
					        <source>Recurring</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">139</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="1421663004162437543" datatype="html">
 | 
				
			||||||
 | 
					        <source>Trigger is recurring.</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">139</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="5937989815294159481" datatype="html">
 | 
				
			||||||
 | 
					        <source>Recurring interval days</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">143</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="722765958672682251" datatype="html">
 | 
				
			||||||
 | 
					        <source>Repeat the trigger every n days.</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">143</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8727727835543352574" datatype="html">
 | 
					      <trans-unit id="8727727835543352574" datatype="html">
 | 
				
			||||||
        <source>Trigger for documents that match <x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="<em>"/>all<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="</em>"/> filters specified below.</source>
 | 
					        <source>Trigger for documents that match <x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="<em>"/>all<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="</em>"/> filters specified below.</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">122</context>
 | 
					          <context context-type="linenumber">148</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="7467799586957602479" datatype="html">
 | 
					      <trans-unit id="7467799586957602479" datatype="html">
 | 
				
			||||||
        <source>Filter filename</source>
 | 
					        <source>Filter filename</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">125</context>
 | 
					          <context context-type="linenumber">151</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3694878959415278689" datatype="html">
 | 
					      <trans-unit id="3694878959415278689" datatype="html">
 | 
				
			||||||
        <source>Apply to documents that match this filename. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.</source>
 | 
					        <source>Apply to documents that match this filename. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">125</context>
 | 
					          <context context-type="linenumber">151</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1473412958770421458" datatype="html">
 | 
					      <trans-unit id="1473412958770421458" datatype="html">
 | 
				
			||||||
        <source>Filter sources</source>
 | 
					        <source>Filter sources</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">127</context>
 | 
					          <context context-type="linenumber">153</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6540860478788535250" datatype="html">
 | 
					      <trans-unit id="6540860478788535250" datatype="html">
 | 
				
			||||||
        <source>Filter path</source>
 | 
					        <source>Filter path</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">128</context>
 | 
					          <context context-type="linenumber">154</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="5491897741674893121" datatype="html">
 | 
					      <trans-unit id="5491897741674893121" datatype="html">
 | 
				
			||||||
        <source>Apply to documents that match this path. Wildcards specified as * are allowed. Case-normalized.</a></source>
 | 
					        <source>Apply to documents that match this path. Wildcards specified as * are allowed. Case-normalized.</a></source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">128</context>
 | 
					          <context context-type="linenumber">154</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="7468453896129193641" datatype="html">
 | 
					      <trans-unit id="7468453896129193641" datatype="html">
 | 
				
			||||||
        <source>Filter mail rule</source>
 | 
					        <source>Filter mail rule</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">129</context>
 | 
					          <context context-type="linenumber">155</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8663702115863339485" datatype="html">
 | 
					      <trans-unit id="8663702115863339485" datatype="html">
 | 
				
			||||||
        <source>Apply to documents consumed via this mail rule.</source>
 | 
					        <source>Apply to documents consumed via this mail rule.</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">129</context>
 | 
					          <context context-type="linenumber">155</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6840369584127435743" datatype="html">
 | 
					      <trans-unit id="6840369584127435743" datatype="html">
 | 
				
			||||||
        <source>Content matching algorithm</source>
 | 
					        <source>Content matching algorithm</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">132</context>
 | 
					          <context context-type="linenumber">158</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="510635115034690805" datatype="html">
 | 
					      <trans-unit id="510635115034690805" datatype="html">
 | 
				
			||||||
        <source>Content matching pattern</source>
 | 
					        <source>Content matching pattern</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">134</context>
 | 
					          <context context-type="linenumber">160</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3484236514968690689" datatype="html">
 | 
					      <trans-unit id="3484236514968690689" datatype="html">
 | 
				
			||||||
        <source>Has any of tags</source>
 | 
					        <source>Has any of tags</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">143</context>
 | 
					          <context context-type="linenumber">169</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="5281365940563983618" datatype="html">
 | 
					      <trans-unit id="5281365940563983618" datatype="html">
 | 
				
			||||||
        <source>Has correspondent</source>
 | 
					        <source>Has correspondent</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">144</context>
 | 
					          <context context-type="linenumber">170</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="4806713133917046341" datatype="html">
 | 
					      <trans-unit id="4806713133917046341" datatype="html">
 | 
				
			||||||
        <source>Has document type</source>
 | 
					        <source>Has document type</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">145</context>
 | 
					          <context context-type="linenumber">171</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6417103744331194518" datatype="html">
 | 
					      <trans-unit id="6417103744331194518" datatype="html">
 | 
				
			||||||
        <source>Action type</source>
 | 
					        <source>Action type</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">155</context>
 | 
					          <context context-type="linenumber">181</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6019822389883736115" datatype="html">
 | 
					      <trans-unit id="6019822389883736115" datatype="html">
 | 
				
			||||||
        <source>Assign title</source>
 | 
					        <source>Assign title</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">160</context>
 | 
					          <context context-type="linenumber">186</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1098196422099517191" datatype="html">
 | 
					      <trans-unit id="1098196422099517191" datatype="html">
 | 
				
			||||||
        <source>Can include some placeholders, see <a target='_blank' href='https://docs.paperless-ngx.com/usage/#workflows'>documentation</a>.</source>
 | 
					        <source>Can include some placeholders, see <a target='_blank' href='https://docs.paperless-ngx.com/usage/#workflows'>documentation</a>.</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">160</context>
 | 
					          <context context-type="linenumber">186</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6528897010417701530" datatype="html">
 | 
					      <trans-unit id="6528897010417701530" datatype="html">
 | 
				
			||||||
        <source>Assign tags</source>
 | 
					        <source>Assign tags</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">161</context>
 | 
					          <context context-type="linenumber">187</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="7198346314713788799" datatype="html">
 | 
					      <trans-unit id="7198346314713788799" datatype="html">
 | 
				
			||||||
        <source>Assign storage path</source>
 | 
					        <source>Assign storage path</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">164</context>
 | 
					          <context context-type="linenumber">190</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="475685412372379925" datatype="html">
 | 
					      <trans-unit id="475685412372379925" datatype="html">
 | 
				
			||||||
        <source>Assign custom fields</source>
 | 
					        <source>Assign custom fields</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">165</context>
 | 
					          <context context-type="linenumber">191</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="5057200219587080996" datatype="html">
 | 
					      <trans-unit id="5057200219587080996" datatype="html">
 | 
				
			||||||
        <source>Assign owner</source>
 | 
					        <source>Assign owner</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">168</context>
 | 
					          <context context-type="linenumber">194</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1749184201773078639" datatype="html">
 | 
					      <trans-unit id="1749184201773078639" datatype="html">
 | 
				
			||||||
        <source>Assign view permissions</source>
 | 
					        <source>Assign view permissions</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">170</context>
 | 
					          <context context-type="linenumber">196</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1744964187586405039" datatype="html">
 | 
					      <trans-unit id="1744964187586405039" datatype="html">
 | 
				
			||||||
        <source>Assign edit permissions</source>
 | 
					        <source>Assign edit permissions</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">189</context>
 | 
					          <context context-type="linenumber">215</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6236311670364192011" datatype="html">
 | 
					      <trans-unit id="6236311670364192011" datatype="html">
 | 
				
			||||||
        <source>Remove tags</source>
 | 
					        <source>Remove tags</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">216</context>
 | 
					          <context context-type="linenumber">242</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="7890599006071681081" datatype="html">
 | 
					      <trans-unit id="7890599006071681081" datatype="html">
 | 
				
			||||||
        <source>Remove all</source>
 | 
					        <source>Remove all</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">217</context>
 | 
					          <context context-type="linenumber">243</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">223</context>
 | 
					          <context context-type="linenumber">249</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">229</context>
 | 
					          <context context-type="linenumber">255</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">235</context>
 | 
					          <context context-type="linenumber">261</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">241</context>
 | 
					          <context context-type="linenumber">267</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">248</context>
 | 
					          <context context-type="linenumber">274</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">254</context>
 | 
					          <context context-type="linenumber">280</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8636414563726517994" datatype="html">
 | 
					      <trans-unit id="8636414563726517994" datatype="html">
 | 
				
			||||||
        <source>Remove correspondents</source>
 | 
					        <source>Remove correspondents</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">222</context>
 | 
					          <context context-type="linenumber">248</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="5305293055593064952" datatype="html">
 | 
					      <trans-unit id="5305293055593064952" datatype="html">
 | 
				
			||||||
        <source>Remove document types</source>
 | 
					        <source>Remove document types</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">228</context>
 | 
					          <context context-type="linenumber">254</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="2400388879708187" datatype="html">
 | 
					      <trans-unit id="2400388879708187" datatype="html">
 | 
				
			||||||
        <source>Remove storage paths</source>
 | 
					        <source>Remove storage paths</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">234</context>
 | 
					          <context context-type="linenumber">260</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="4324304327041955720" datatype="html">
 | 
					      <trans-unit id="4324304327041955720" datatype="html">
 | 
				
			||||||
        <source>Remove custom fields</source>
 | 
					        <source>Remove custom fields</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">240</context>
 | 
					          <context context-type="linenumber">266</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8367536502602515064" datatype="html">
 | 
					      <trans-unit id="8367536502602515064" datatype="html">
 | 
				
			||||||
        <source>Remove owners</source>
 | 
					        <source>Remove owners</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">247</context>
 | 
					          <context context-type="linenumber">273</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3393772184866313281" datatype="html">
 | 
					      <trans-unit id="3393772184866313281" datatype="html">
 | 
				
			||||||
        <source>Remove permissions</source>
 | 
					        <source>Remove permissions</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">253</context>
 | 
					          <context context-type="linenumber">279</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3145629643370481114" datatype="html">
 | 
					      <trans-unit id="3145629643370481114" datatype="html">
 | 
				
			||||||
        <source>View permissions</source>
 | 
					        <source>View permissions</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">256</context>
 | 
					          <context context-type="linenumber">282</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1946660694635960249" datatype="html">
 | 
					      <trans-unit id="1946660694635960249" datatype="html">
 | 
				
			||||||
        <source>Edit permissions</source>
 | 
					        <source>Edit permissions</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">275</context>
 | 
					          <context context-type="linenumber">301</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="4626030417479279989" datatype="html">
 | 
					      <trans-unit id="4626030417479279989" datatype="html">
 | 
				
			||||||
        <source>Consume Folder</source>
 | 
					        <source>Consume Folder</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">39</context>
 | 
					          <context context-type="linenumber">40</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="526966086395145275" datatype="html">
 | 
					      <trans-unit id="526966086395145275" datatype="html">
 | 
				
			||||||
        <source>API Upload</source>
 | 
					        <source>API Upload</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">43</context>
 | 
					          <context context-type="linenumber">44</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="7502272564743467653" datatype="html">
 | 
					      <trans-unit id="7502272564743467653" datatype="html">
 | 
				
			||||||
        <source>Mail Fetch</source>
 | 
					        <source>Mail Fetch</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">47</context>
 | 
					          <context context-type="linenumber">48</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="3553216189604488439" datatype="html">
 | 
				
			||||||
 | 
					        <source>Modified</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">63</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/data/document.ts</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">99</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="8686921715946540725" datatype="html">
 | 
				
			||||||
 | 
					        <source>Custom Field</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">67</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8696908693776094667" datatype="html">
 | 
					      <trans-unit id="8696908693776094667" datatype="html">
 | 
				
			||||||
        <source>Consumption Started</source>
 | 
					        <source>Consumption Started</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">54</context>
 | 
					          <context context-type="linenumber">74</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="7858311467093621703" datatype="html">
 | 
					      <trans-unit id="7858311467093621703" datatype="html">
 | 
				
			||||||
        <source>Document Added</source>
 | 
					        <source>Document Added</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">58</context>
 | 
					          <context context-type="linenumber">78</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="7955486237346046731" datatype="html">
 | 
					      <trans-unit id="7955486237346046731" datatype="html">
 | 
				
			||||||
        <source>Document Updated</source>
 | 
					        <source>Document Updated</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">62</context>
 | 
					          <context context-type="linenumber">82</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="9172233176401579786" datatype="html">
 | 
				
			||||||
 | 
					        <source>Scheduled</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">86</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="5502398334173581061" datatype="html">
 | 
					      <trans-unit id="5502398334173581061" datatype="html">
 | 
				
			||||||
        <source>Assignment</source>
 | 
					        <source>Assignment</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">69</context>
 | 
					          <context context-type="linenumber">93</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6234812824772766804" datatype="html">
 | 
					      <trans-unit id="6234812824772766804" datatype="html">
 | 
				
			||||||
        <source>Removal</source>
 | 
					        <source>Removal</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">73</context>
 | 
					          <context context-type="linenumber">97</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3138206142174978019" datatype="html">
 | 
					      <trans-unit id="3138206142174978019" datatype="html">
 | 
				
			||||||
        <source>Create new workflow</source>
 | 
					        <source>Create new workflow</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">142</context>
 | 
					          <context context-type="linenumber">172</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="5996779210524133604" datatype="html">
 | 
					      <trans-unit id="5996779210524133604" datatype="html">
 | 
				
			||||||
        <source>Edit workflow</source>
 | 
					        <source>Edit workflow</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">146</context>
 | 
					          <context context-type="linenumber">176</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6381578200008167206" datatype="html">
 | 
					      <trans-unit id="6381578200008167206" datatype="html">
 | 
				
			||||||
@ -8480,13 +8583,6 @@
 | 
				
			|||||||
          <context context-type="linenumber">46</context>
 | 
					          <context context-type="linenumber">46</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3553216189604488439" datatype="html">
 | 
					 | 
				
			||||||
        <source>Modified</source>
 | 
					 | 
				
			||||||
        <context-group purpose="location">
 | 
					 | 
				
			||||||
          <context context-type="sourcefile">src/app/data/document.ts</context>
 | 
					 | 
				
			||||||
          <context context-type="linenumber">99</context>
 | 
					 | 
				
			||||||
        </context-group>
 | 
					 | 
				
			||||||
      </trans-unit>
 | 
					 | 
				
			||||||
      <trans-unit id="4460262093225954455" datatype="html">
 | 
					      <trans-unit id="4460262093225954455" datatype="html">
 | 
				
			||||||
        <source>Search score</source>
 | 
					        <source>Search score</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
				
			|||||||
@ -119,6 +119,32 @@
 | 
				
			|||||||
  <div [formGroup]="formGroup">
 | 
					  <div [formGroup]="formGroup">
 | 
				
			||||||
    <input type="hidden" formControlName="id" />
 | 
					    <input type="hidden" formControlName="id" />
 | 
				
			||||||
    <pngx-input-select i18n-title title="Trigger type" [horizontal]="true" [items]="triggerTypeOptions" formControlName="type"></pngx-input-select>
 | 
					    <pngx-input-select i18n-title title="Trigger type" [horizontal]="true" [items]="triggerTypeOptions" formControlName="type"></pngx-input-select>
 | 
				
			||||||
 | 
					    @if (formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
 | 
				
			||||||
 | 
					      <p class="small" i18n>Set scheduled trigger offset and which field to use.</p>
 | 
				
			||||||
 | 
					      <div class="row">
 | 
				
			||||||
 | 
					        <div class="col-4">
 | 
				
			||||||
 | 
					          <pngx-input-number i18n-title title="Offset days" formControlName="schedule_offset_days" i18n-hint hint="Use 0 for immediate." [showAdd]="false" [error]="error?.schedule_offset_days"></pngx-input-number>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="col-4">
 | 
				
			||||||
 | 
					          <pngx-input-select i18n-title title="Relative to" formControlName="schedule_date_field" [items]="scheduleDateFieldOptions" [error]="error?.schedule_date_field"></pngx-input-select>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        @if (formGroup.get('schedule_date_field').value === 'custom_field') {
 | 
				
			||||||
 | 
					          <div class="col-4">
 | 
				
			||||||
 | 
					            <pngx-input-select i18n-title title="Delay custom field" formControlName="schedule_date_custom_field" [items]="dateCustomFields" i18n-hint hint="Custom field to use for date." [error]="error?.schedule_date_custom_field"></pngx-input-select>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="row">
 | 
				
			||||||
 | 
					        <div class="col-4">
 | 
				
			||||||
 | 
					          <pngx-input-check i18n-title title="Recurring" formControlName="schedule_is_recurring" i18n-hint hint="Trigger is recurring." [error]="error?.schedule_is_recurring"></pngx-input-check>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="col-4">
 | 
				
			||||||
 | 
					          @if (formGroup.get('schedule_is_recurring').value === true) {
 | 
				
			||||||
 | 
					            <pngx-input-number i18n-title title="Recurring interval days" formControlName="schedule_recurring_interval_days" i18n-hint hint="Repeat the trigger every n days." [showAdd]="false" [error]="error?.schedule_recurring_interval_days"></pngx-input-number>
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    <p class="small" i18n>Trigger for documents that match <em>all</em> filters specified below.</p>
 | 
					    <p class="small" i18n>Trigger for documents that match <em>all</em> filters specified below.</p>
 | 
				
			||||||
    <div class="row">
 | 
					    <div class="row">
 | 
				
			||||||
      <div class="col">
 | 
					      <div class="col">
 | 
				
			||||||
@ -128,7 +154,7 @@
 | 
				
			|||||||
          <pngx-input-text i18n-title title="Filter path" formControlName="filter_path" i18n-hint hint="Apply to documents that match this path. Wildcards specified as * are allowed. Case-normalized.</a>" [error]="error?.filter_path"></pngx-input-text>
 | 
					          <pngx-input-text i18n-title title="Filter path" formControlName="filter_path" i18n-hint hint="Apply to documents that match this path. Wildcards specified as * are allowed. Case-normalized.</a>" [error]="error?.filter_path"></pngx-input-text>
 | 
				
			||||||
          <pngx-input-select i18n-title title="Filter mail rule" [items]="mailRules" [allowNull]="true" formControlName="filter_mailrule" i18n-hint hint="Apply to documents consumed via this mail rule." [error]="error?.filter_mailrule"></pngx-input-select>
 | 
					          <pngx-input-select i18n-title title="Filter mail rule" [items]="mailRules" [allowNull]="true" formControlName="filter_mailrule" i18n-hint hint="Apply to documents consumed via this mail rule." [error]="error?.filter_mailrule"></pngx-input-select>
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        @if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated) {
 | 
					        @if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated || formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
 | 
				
			||||||
          <pngx-input-select i18n-title title="Content matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
 | 
					          <pngx-input-select i18n-title title="Content matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
 | 
				
			||||||
          @if (patternRequired) {
 | 
					          @if (patternRequired) {
 | 
				
			||||||
            <pngx-input-text i18n-title title="Content matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
 | 
					            <pngx-input-text i18n-title title="Content matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
 | 
				
			||||||
@ -138,7 +164,7 @@
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      @if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated) {
 | 
					      @if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated || formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
 | 
				
			||||||
        <div class="col-md-6">
 | 
					        <div class="col-md-6">
 | 
				
			||||||
          <pngx-input-tags [allowCreate]="false" i18n-title title="Has any of tags" formControlName="filter_has_tags"></pngx-input-tags>
 | 
					          <pngx-input-tags [allowCreate]="false" i18n-title title="Has any of tags" formControlName="filter_has_tags"></pngx-input-tags>
 | 
				
			||||||
          <pngx-input-select i18n-title title="Has correspondent" [items]="correspondents" [allowNull]="true" formControlName="filter_has_correspondent"></pngx-input-select>
 | 
					          <pngx-input-select i18n-title title="Has correspondent" [items]="correspondents" [allowNull]="true" formControlName="filter_has_correspondent"></pngx-input-select>
 | 
				
			||||||
 | 
				
			|||||||
@ -22,6 +22,7 @@ import { SwitchComponent } from '../../input/switch/switch.component'
 | 
				
			|||||||
import { EditDialogMode } from '../edit-dialog.component'
 | 
					import { EditDialogMode } from '../edit-dialog.component'
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  DOCUMENT_SOURCE_OPTIONS,
 | 
					  DOCUMENT_SOURCE_OPTIONS,
 | 
				
			||||||
 | 
					  SCHEDULE_DATE_FIELD_OPTIONS,
 | 
				
			||||||
  WORKFLOW_ACTION_OPTIONS,
 | 
					  WORKFLOW_ACTION_OPTIONS,
 | 
				
			||||||
  WORKFLOW_TYPE_OPTIONS,
 | 
					  WORKFLOW_TYPE_OPTIONS,
 | 
				
			||||||
  WorkflowEditDialogComponent,
 | 
					  WorkflowEditDialogComponent,
 | 
				
			||||||
@ -40,6 +41,7 @@ import {
 | 
				
			|||||||
import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model'
 | 
					import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model'
 | 
				
			||||||
import { ConfirmButtonComponent } from '../../confirm-button/confirm-button.component'
 | 
					import { ConfirmButtonComponent } from '../../confirm-button/confirm-button.component'
 | 
				
			||||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
 | 
					import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
 | 
				
			||||||
 | 
					import { CustomFieldDataType } from 'src/app/data/custom-field'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const workflow: Workflow = {
 | 
					const workflow: Workflow = {
 | 
				
			||||||
  name: 'Workflow 1',
 | 
					  name: 'Workflow 1',
 | 
				
			||||||
@ -148,7 +150,18 @@ describe('WorkflowEditDialogComponent', () => {
 | 
				
			|||||||
          useValue: {
 | 
					          useValue: {
 | 
				
			||||||
            listAll: () =>
 | 
					            listAll: () =>
 | 
				
			||||||
              of({
 | 
					              of({
 | 
				
			||||||
                results: [],
 | 
					                results: [
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    id: 1,
 | 
				
			||||||
 | 
					                    name: 'cf1',
 | 
				
			||||||
 | 
					                    data_type: CustomFieldDataType.String,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    id: 2,
 | 
				
			||||||
 | 
					                    name: 'cf2',
 | 
				
			||||||
 | 
					                    data_type: CustomFieldDataType.Date,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
              }),
 | 
					              }),
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -186,7 +199,7 @@ describe('WorkflowEditDialogComponent', () => {
 | 
				
			|||||||
    expect(editTitleSpy).toHaveBeenCalled()
 | 
					    expect(editTitleSpy).toHaveBeenCalled()
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should return source options, type options, type name', () => {
 | 
					  it('should return source options, type options, type name, schedule date field options', () => {
 | 
				
			||||||
    // coverage
 | 
					    // coverage
 | 
				
			||||||
    expect(component.sourceOptions).toEqual(DOCUMENT_SOURCE_OPTIONS)
 | 
					    expect(component.sourceOptions).toEqual(DOCUMENT_SOURCE_OPTIONS)
 | 
				
			||||||
    expect(component.triggerTypeOptions).toEqual(WORKFLOW_TYPE_OPTIONS)
 | 
					    expect(component.triggerTypeOptions).toEqual(WORKFLOW_TYPE_OPTIONS)
 | 
				
			||||||
@ -200,6 +213,9 @@ describe('WorkflowEditDialogComponent', () => {
 | 
				
			|||||||
      component.getActionTypeOptionName(WorkflowActionType.Assignment)
 | 
					      component.getActionTypeOptionName(WorkflowActionType.Assignment)
 | 
				
			||||||
    ).toEqual('Assignment')
 | 
					    ).toEqual('Assignment')
 | 
				
			||||||
    expect(component.getActionTypeOptionName(null)).toEqual('')
 | 
					    expect(component.getActionTypeOptionName(null)).toEqual('')
 | 
				
			||||||
 | 
					    expect(component.scheduleDateFieldOptions).toEqual(
 | 
				
			||||||
 | 
					      SCHEDULE_DATE_FIELD_OPTIONS
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should support add and remove triggers and actions', () => {
 | 
					  it('should support add and remove triggers and actions', () => {
 | 
				
			||||||
 | 
				
			|||||||
@ -16,9 +16,10 @@ import { EditDialogComponent } from '../edit-dialog.component'
 | 
				
			|||||||
import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
 | 
					import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
 | 
				
			||||||
import { MailRule } from 'src/app/data/mail-rule'
 | 
					import { MailRule } from 'src/app/data/mail-rule'
 | 
				
			||||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
 | 
					import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
 | 
				
			||||||
import { CustomField } from 'src/app/data/custom-field'
 | 
					import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  DocumentSource,
 | 
					  DocumentSource,
 | 
				
			||||||
 | 
					  ScheduleDateField,
 | 
				
			||||||
  WorkflowTrigger,
 | 
					  WorkflowTrigger,
 | 
				
			||||||
  WorkflowTriggerType,
 | 
					  WorkflowTriggerType,
 | 
				
			||||||
} from 'src/app/data/workflow-trigger'
 | 
					} from 'src/app/data/workflow-trigger'
 | 
				
			||||||
@ -48,6 +49,25 @@ export const DOCUMENT_SOURCE_OPTIONS = [
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const SCHEDULE_DATE_FIELD_OPTIONS = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: ScheduleDateField.Added,
 | 
				
			||||||
 | 
					    name: $localize`Added`,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: ScheduleDateField.Created,
 | 
				
			||||||
 | 
					    name: $localize`Created`,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: ScheduleDateField.Modified,
 | 
				
			||||||
 | 
					    name: $localize`Modified`,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: ScheduleDateField.CustomField,
 | 
				
			||||||
 | 
					    name: $localize`Custom Field`,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const WORKFLOW_TYPE_OPTIONS = [
 | 
					export const WORKFLOW_TYPE_OPTIONS = [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    id: WorkflowTriggerType.Consumption,
 | 
					    id: WorkflowTriggerType.Consumption,
 | 
				
			||||||
@ -61,6 +81,10 @@ export const WORKFLOW_TYPE_OPTIONS = [
 | 
				
			|||||||
    id: WorkflowTriggerType.DocumentUpdated,
 | 
					    id: WorkflowTriggerType.DocumentUpdated,
 | 
				
			||||||
    name: $localize`Document Updated`,
 | 
					    name: $localize`Document Updated`,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: WorkflowTriggerType.Scheduled,
 | 
				
			||||||
 | 
					    name: $localize`Scheduled`,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const WORKFLOW_ACTION_OPTIONS = [
 | 
					export const WORKFLOW_ACTION_OPTIONS = [
 | 
				
			||||||
@ -96,6 +120,7 @@ export class WorkflowEditDialogComponent
 | 
				
			|||||||
  storagePaths: StoragePath[]
 | 
					  storagePaths: StoragePath[]
 | 
				
			||||||
  mailRules: MailRule[]
 | 
					  mailRules: MailRule[]
 | 
				
			||||||
  customFields: CustomField[]
 | 
					  customFields: CustomField[]
 | 
				
			||||||
 | 
					  dateCustomFields: CustomField[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  expandedItem: number = null
 | 
					  expandedItem: number = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -135,7 +160,12 @@ export class WorkflowEditDialogComponent
 | 
				
			|||||||
    customFieldsService
 | 
					    customFieldsService
 | 
				
			||||||
      .listAll()
 | 
					      .listAll()
 | 
				
			||||||
      .pipe(first())
 | 
					      .pipe(first())
 | 
				
			||||||
      .subscribe((result) => (this.customFields = result.results))
 | 
					      .subscribe((result) => {
 | 
				
			||||||
 | 
					        this.customFields = result.results
 | 
				
			||||||
 | 
					        this.dateCustomFields = this.customFields?.filter(
 | 
				
			||||||
 | 
					          (f) => f.data_type === CustomFieldDataType.Date
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getCreateTitle() {
 | 
					  getCreateTitle() {
 | 
				
			||||||
@ -314,6 +344,15 @@ export class WorkflowEditDialogComponent
 | 
				
			|||||||
        filter_has_document_type: new FormControl(
 | 
					        filter_has_document_type: new FormControl(
 | 
				
			||||||
          trigger.filter_has_document_type
 | 
					          trigger.filter_has_document_type
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 | 
					        schedule_offset_days: new FormControl(trigger.schedule_offset_days),
 | 
				
			||||||
 | 
					        schedule_is_recurring: new FormControl(trigger.schedule_is_recurring),
 | 
				
			||||||
 | 
					        schedule_recurring_interval_days: new FormControl(
 | 
				
			||||||
 | 
					          trigger.schedule_recurring_interval_days
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        schedule_date_field: new FormControl(trigger.schedule_date_field),
 | 
				
			||||||
 | 
					        schedule_date_custom_field: new FormControl(
 | 
				
			||||||
 | 
					          trigger.schedule_date_custom_field
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
      { emitEvent }
 | 
					      { emitEvent }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@ -388,6 +427,10 @@ export class WorkflowEditDialogComponent
 | 
				
			|||||||
    return WORKFLOW_TYPE_OPTIONS
 | 
					    return WORKFLOW_TYPE_OPTIONS
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get scheduleDateFieldOptions() {
 | 
				
			||||||
 | 
					    return SCHEDULE_DATE_FIELD_OPTIONS
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getTriggerTypeOptionName(type: WorkflowTriggerType): string {
 | 
					  getTriggerTypeOptionName(type: WorkflowTriggerType): string {
 | 
				
			||||||
    return this.triggerTypeOptions.find((t) => t.id === type)?.name ?? ''
 | 
					    return this.triggerTypeOptions.find((t) => t.id === type)?.name ?? ''
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -408,6 +451,11 @@ export class WorkflowEditDialogComponent
 | 
				
			|||||||
      matching_algorithm: MATCH_NONE,
 | 
					      matching_algorithm: MATCH_NONE,
 | 
				
			||||||
      match: '',
 | 
					      match: '',
 | 
				
			||||||
      is_insensitive: true,
 | 
					      is_insensitive: true,
 | 
				
			||||||
 | 
					      schedule_offset_days: 0,
 | 
				
			||||||
 | 
					      schedule_is_recurring: false,
 | 
				
			||||||
 | 
					      schedule_recurring_interval_days: 1,
 | 
				
			||||||
 | 
					      schedule_date_field: ScheduleDateField.Added,
 | 
				
			||||||
 | 
					      schedule_date_custom_field: null,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.object.triggers.push(trigger)
 | 
					    this.object.triggers.push(trigger)
 | 
				
			||||||
    this.createTriggerField(trigger)
 | 
					    this.createTriggerField(trigger)
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,14 @@ export enum WorkflowTriggerType {
 | 
				
			|||||||
  Consumption = 1,
 | 
					  Consumption = 1,
 | 
				
			||||||
  DocumentAdded = 2,
 | 
					  DocumentAdded = 2,
 | 
				
			||||||
  DocumentUpdated = 3,
 | 
					  DocumentUpdated = 3,
 | 
				
			||||||
 | 
					  Scheduled = 4,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum ScheduleDateField {
 | 
				
			||||||
 | 
					  Added = 'added',
 | 
				
			||||||
 | 
					  Created = 'created',
 | 
				
			||||||
 | 
					  Modified = 'modified',
 | 
				
			||||||
 | 
					  CustomField = 'custom_field',
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface WorkflowTrigger extends ObjectWithId {
 | 
					export interface WorkflowTrigger extends ObjectWithId {
 | 
				
			||||||
@ -34,4 +42,14 @@ export interface WorkflowTrigger extends ObjectWithId {
 | 
				
			|||||||
  filter_has_correspondent?: number // Correspondent.id
 | 
					  filter_has_correspondent?: number // Correspondent.id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  filter_has_document_type?: number // DocumentType.id
 | 
					  filter_has_document_type?: number // DocumentType.id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  schedule_offset_days?: number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  schedule_is_recurring?: boolean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  schedule_recurring_interval_days?: number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  schedule_date_field?: ScheduleDateField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  schedule_date_custom_field?: number // CustomField.id
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -409,6 +409,7 @@ def document_matches_workflow(
 | 
				
			|||||||
            elif (
 | 
					            elif (
 | 
				
			||||||
                trigger_type == WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED
 | 
					                trigger_type == WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED
 | 
				
			||||||
                or trigger_type == WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED
 | 
					                or trigger_type == WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED
 | 
				
			||||||
 | 
					                or trigger_type == WorkflowTrigger.WorkflowTriggerType.SCHEDULED
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                trigger_matched, reason = existing_document_matches_workflow(
 | 
					                trigger_matched, reason = existing_document_matches_workflow(
 | 
				
			||||||
                    document,
 | 
					                    document,
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					# Generated by Django 5.1.1 on 2024-11-05 05:19
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import django.core.validators
 | 
				
			||||||
 | 
					import django.db.models.deletion
 | 
				
			||||||
 | 
					import django.utils.timezone
 | 
				
			||||||
 | 
					from django.db import migrations
 | 
				
			||||||
 | 
					from django.db import models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ("documents", "1057_paperlesstask_owner"),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name="workflowtrigger",
 | 
				
			||||||
 | 
					            name="schedule_date_custom_field",
 | 
				
			||||||
 | 
					            field=models.ForeignKey(
 | 
				
			||||||
 | 
					                blank=True,
 | 
				
			||||||
 | 
					                null=True,
 | 
				
			||||||
 | 
					                on_delete=django.db.models.deletion.SET_NULL,
 | 
				
			||||||
 | 
					                to="documents.customfield",
 | 
				
			||||||
 | 
					                verbose_name="schedule date custom field",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name="workflowtrigger",
 | 
				
			||||||
 | 
					            name="schedule_date_field",
 | 
				
			||||||
 | 
					            field=models.CharField(
 | 
				
			||||||
 | 
					                choices=[
 | 
				
			||||||
 | 
					                    ("added", "Added"),
 | 
				
			||||||
 | 
					                    ("created", "Created"),
 | 
				
			||||||
 | 
					                    ("modified", "Modified"),
 | 
				
			||||||
 | 
					                    ("custom_field", "Custom Field"),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                default="added",
 | 
				
			||||||
 | 
					                help_text="The field to check for a schedule trigger.",
 | 
				
			||||||
 | 
					                max_length=20,
 | 
				
			||||||
 | 
					                verbose_name="schedule date field",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name="workflowtrigger",
 | 
				
			||||||
 | 
					            name="schedule_is_recurring",
 | 
				
			||||||
 | 
					            field=models.BooleanField(
 | 
				
			||||||
 | 
					                default=False,
 | 
				
			||||||
 | 
					                help_text="If the schedule should be recurring.",
 | 
				
			||||||
 | 
					                verbose_name="schedule is recurring",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name="workflowtrigger",
 | 
				
			||||||
 | 
					            name="schedule_offset_days",
 | 
				
			||||||
 | 
					            field=models.PositiveIntegerField(
 | 
				
			||||||
 | 
					                default=0,
 | 
				
			||||||
 | 
					                help_text="The number of days to offset the schedule trigger by.",
 | 
				
			||||||
 | 
					                verbose_name="schedule offset days",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name="workflowtrigger",
 | 
				
			||||||
 | 
					            name="schedule_recurring_interval_days",
 | 
				
			||||||
 | 
					            field=models.PositiveIntegerField(
 | 
				
			||||||
 | 
					                default=1,
 | 
				
			||||||
 | 
					                help_text="The number of days between recurring schedule triggers.",
 | 
				
			||||||
 | 
					                validators=[django.core.validators.MinValueValidator(1)],
 | 
				
			||||||
 | 
					                verbose_name="schedule recurring delay in days",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name="workflowtrigger",
 | 
				
			||||||
 | 
					            name="type",
 | 
				
			||||||
 | 
					            field=models.PositiveIntegerField(
 | 
				
			||||||
 | 
					                choices=[
 | 
				
			||||||
 | 
					                    (1, "Consumption Started"),
 | 
				
			||||||
 | 
					                    (2, "Document Added"),
 | 
				
			||||||
 | 
					                    (3, "Document Updated"),
 | 
				
			||||||
 | 
					                    (4, "Scheduled"),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                default=1,
 | 
				
			||||||
 | 
					                verbose_name="Workflow Trigger Type",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.CreateModel(
 | 
				
			||||||
 | 
					            name="WorkflowRun",
 | 
				
			||||||
 | 
					            fields=[
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    "id",
 | 
				
			||||||
 | 
					                    models.AutoField(
 | 
				
			||||||
 | 
					                        auto_created=True,
 | 
				
			||||||
 | 
					                        primary_key=True,
 | 
				
			||||||
 | 
					                        serialize=False,
 | 
				
			||||||
 | 
					                        verbose_name="ID",
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    "type",
 | 
				
			||||||
 | 
					                    models.PositiveIntegerField(
 | 
				
			||||||
 | 
					                        choices=[
 | 
				
			||||||
 | 
					                            (1, "Consumption Started"),
 | 
				
			||||||
 | 
					                            (2, "Document Added"),
 | 
				
			||||||
 | 
					                            (3, "Document Updated"),
 | 
				
			||||||
 | 
					                            (4, "Scheduled"),
 | 
				
			||||||
 | 
					                        ],
 | 
				
			||||||
 | 
					                        null=True,
 | 
				
			||||||
 | 
					                        verbose_name="workflow trigger type",
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    "run_at",
 | 
				
			||||||
 | 
					                    models.DateTimeField(
 | 
				
			||||||
 | 
					                        db_index=True,
 | 
				
			||||||
 | 
					                        default=django.utils.timezone.now,
 | 
				
			||||||
 | 
					                        verbose_name="date run",
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    "document",
 | 
				
			||||||
 | 
					                    models.ForeignKey(
 | 
				
			||||||
 | 
					                        null=True,
 | 
				
			||||||
 | 
					                        on_delete=django.db.models.deletion.CASCADE,
 | 
				
			||||||
 | 
					                        related_name="workflow_runs",
 | 
				
			||||||
 | 
					                        to="documents.document",
 | 
				
			||||||
 | 
					                        verbose_name="document",
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    "workflow",
 | 
				
			||||||
 | 
					                    models.ForeignKey(
 | 
				
			||||||
 | 
					                        on_delete=django.db.models.deletion.CASCADE,
 | 
				
			||||||
 | 
					                        related_name="runs",
 | 
				
			||||||
 | 
					                        to="documents.workflow",
 | 
				
			||||||
 | 
					                        verbose_name="workflow",
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            options={
 | 
				
			||||||
 | 
					                "verbose_name": "workflow run",
 | 
				
			||||||
 | 
					                "verbose_name_plural": "workflow runs",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@ -1016,12 +1016,19 @@ class WorkflowTrigger(models.Model):
 | 
				
			|||||||
        CONSUMPTION = 1, _("Consumption Started")
 | 
					        CONSUMPTION = 1, _("Consumption Started")
 | 
				
			||||||
        DOCUMENT_ADDED = 2, _("Document Added")
 | 
					        DOCUMENT_ADDED = 2, _("Document Added")
 | 
				
			||||||
        DOCUMENT_UPDATED = 3, _("Document Updated")
 | 
					        DOCUMENT_UPDATED = 3, _("Document Updated")
 | 
				
			||||||
 | 
					        SCHEDULED = 4, _("Scheduled")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class DocumentSourceChoices(models.IntegerChoices):
 | 
					    class DocumentSourceChoices(models.IntegerChoices):
 | 
				
			||||||
        CONSUME_FOLDER = DocumentSource.ConsumeFolder.value, _("Consume Folder")
 | 
					        CONSUME_FOLDER = DocumentSource.ConsumeFolder.value, _("Consume Folder")
 | 
				
			||||||
        API_UPLOAD = DocumentSource.ApiUpload.value, _("Api Upload")
 | 
					        API_UPLOAD = DocumentSource.ApiUpload.value, _("Api Upload")
 | 
				
			||||||
        MAIL_FETCH = DocumentSource.MailFetch.value, _("Mail Fetch")
 | 
					        MAIL_FETCH = DocumentSource.MailFetch.value, _("Mail Fetch")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class ScheduleDateField(models.TextChoices):
 | 
				
			||||||
 | 
					        ADDED = "added", _("Added")
 | 
				
			||||||
 | 
					        CREATED = "created", _("Created")
 | 
				
			||||||
 | 
					        MODIFIED = "modified", _("Modified")
 | 
				
			||||||
 | 
					        CUSTOM_FIELD = "custom_field", _("Custom Field")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type = models.PositiveIntegerField(
 | 
					    type = models.PositiveIntegerField(
 | 
				
			||||||
        _("Workflow Trigger Type"),
 | 
					        _("Workflow Trigger Type"),
 | 
				
			||||||
        choices=WorkflowTriggerType.choices,
 | 
					        choices=WorkflowTriggerType.choices,
 | 
				
			||||||
@ -1098,6 +1105,49 @@ class WorkflowTrigger(models.Model):
 | 
				
			|||||||
        verbose_name=_("has this correspondent"),
 | 
					        verbose_name=_("has this correspondent"),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_offset_days = models.PositiveIntegerField(
 | 
				
			||||||
 | 
					        _("schedule offset days"),
 | 
				
			||||||
 | 
					        default=0,
 | 
				
			||||||
 | 
					        help_text=_(
 | 
				
			||||||
 | 
					            "The number of days to offset the schedule trigger by.",
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_is_recurring = models.BooleanField(
 | 
				
			||||||
 | 
					        _("schedule is recurring"),
 | 
				
			||||||
 | 
					        default=False,
 | 
				
			||||||
 | 
					        help_text=_(
 | 
				
			||||||
 | 
					            "If the schedule should be recurring.",
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_recurring_interval_days = models.PositiveIntegerField(
 | 
				
			||||||
 | 
					        _("schedule recurring delay in days"),
 | 
				
			||||||
 | 
					        default=1,
 | 
				
			||||||
 | 
					        validators=[MinValueValidator(1)],
 | 
				
			||||||
 | 
					        help_text=_(
 | 
				
			||||||
 | 
					            "The number of days between recurring schedule triggers.",
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_date_field = models.CharField(
 | 
				
			||||||
 | 
					        _("schedule date field"),
 | 
				
			||||||
 | 
					        max_length=20,
 | 
				
			||||||
 | 
					        choices=ScheduleDateField.choices,
 | 
				
			||||||
 | 
					        default=ScheduleDateField.ADDED,
 | 
				
			||||||
 | 
					        help_text=_(
 | 
				
			||||||
 | 
					            "The field to check for a schedule trigger.",
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schedule_date_custom_field = models.ForeignKey(
 | 
				
			||||||
 | 
					        CustomField,
 | 
				
			||||||
 | 
					        null=True,
 | 
				
			||||||
 | 
					        blank=True,
 | 
				
			||||||
 | 
					        on_delete=models.SET_NULL,
 | 
				
			||||||
 | 
					        verbose_name=_("schedule date custom field"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        verbose_name = _("workflow trigger")
 | 
					        verbose_name = _("workflow trigger")
 | 
				
			||||||
        verbose_name_plural = _("workflow triggers")
 | 
					        verbose_name_plural = _("workflow triggers")
 | 
				
			||||||
@ -1348,3 +1398,39 @@ class Workflow(models.Model):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return f"Workflow: {self.name}"
 | 
					        return f"Workflow: {self.name}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WorkflowRun(models.Model):
 | 
				
			||||||
 | 
					    workflow = models.ForeignKey(
 | 
				
			||||||
 | 
					        Workflow,
 | 
				
			||||||
 | 
					        on_delete=models.CASCADE,
 | 
				
			||||||
 | 
					        related_name="runs",
 | 
				
			||||||
 | 
					        verbose_name=_("workflow"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    type = models.PositiveIntegerField(
 | 
				
			||||||
 | 
					        _("workflow trigger type"),
 | 
				
			||||||
 | 
					        choices=WorkflowTrigger.WorkflowTriggerType.choices,
 | 
				
			||||||
 | 
					        null=True,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    document = models.ForeignKey(
 | 
				
			||||||
 | 
					        Document,
 | 
				
			||||||
 | 
					        null=True,
 | 
				
			||||||
 | 
					        on_delete=models.CASCADE,
 | 
				
			||||||
 | 
					        related_name="workflow_runs",
 | 
				
			||||||
 | 
					        verbose_name=_("document"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    run_at = models.DateTimeField(
 | 
				
			||||||
 | 
					        _("date run"),
 | 
				
			||||||
 | 
					        default=timezone.now,
 | 
				
			||||||
 | 
					        db_index=True,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        verbose_name = _("workflow run")
 | 
				
			||||||
 | 
					        verbose_name_plural = _("workflow runs")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        return f"WorkflowRun of {self.workflow} at {self.run_at} on {self.document}"
 | 
				
			||||||
 | 
				
			|||||||
@ -1772,6 +1772,11 @@ class WorkflowTriggerSerializer(serializers.ModelSerializer):
 | 
				
			|||||||
            "filter_has_tags",
 | 
					            "filter_has_tags",
 | 
				
			||||||
            "filter_has_correspondent",
 | 
					            "filter_has_correspondent",
 | 
				
			||||||
            "filter_has_document_type",
 | 
					            "filter_has_document_type",
 | 
				
			||||||
 | 
					            "schedule_offset_days",
 | 
				
			||||||
 | 
					            "schedule_is_recurring",
 | 
				
			||||||
 | 
					            "schedule_recurring_interval_days",
 | 
				
			||||||
 | 
					            "schedule_date_field",
 | 
				
			||||||
 | 
					            "schedule_date_custom_field",
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate(self, attrs):
 | 
					    def validate(self, attrs):
 | 
				
			||||||
 | 
				
			|||||||
@ -37,6 +37,7 @@ from documents.models import PaperlessTask
 | 
				
			|||||||
from documents.models import Tag
 | 
					from documents.models import Tag
 | 
				
			||||||
from documents.models import Workflow
 | 
					from documents.models import Workflow
 | 
				
			||||||
from documents.models import WorkflowAction
 | 
					from documents.models import WorkflowAction
 | 
				
			||||||
 | 
					from documents.models import WorkflowRun
 | 
				
			||||||
from documents.models import WorkflowTrigger
 | 
					from documents.models import WorkflowTrigger
 | 
				
			||||||
from documents.permissions import get_objects_for_user_owner_aware
 | 
					from documents.permissions import get_objects_for_user_owner_aware
 | 
				
			||||||
from documents.permissions import set_permissions_for_object
 | 
					from documents.permissions import set_permissions_for_object
 | 
				
			||||||
@ -916,6 +917,12 @@ def run_workflows(
 | 
				
			|||||||
                document.save()
 | 
					                document.save()
 | 
				
			||||||
                document.tags.set(doc_tag_ids)
 | 
					                document.tags.set(doc_tag_ids)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            WorkflowRun.objects.create(
 | 
				
			||||||
 | 
					                workflow=workflow,
 | 
				
			||||||
 | 
					                type=trigger_type,
 | 
				
			||||||
 | 
					                document=document if not use_overrides else None,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if use_overrides:
 | 
					    if use_overrides:
 | 
				
			||||||
        return overrides, "\n".join(messages)
 | 
					        return overrides, "\n".join(messages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -31,10 +31,14 @@ from documents.double_sided import CollatePlugin
 | 
				
			|||||||
from documents.file_handling import create_source_path_directory
 | 
					from documents.file_handling import create_source_path_directory
 | 
				
			||||||
from documents.file_handling import generate_unique_filename
 | 
					from documents.file_handling import generate_unique_filename
 | 
				
			||||||
from documents.models import Correspondent
 | 
					from documents.models import Correspondent
 | 
				
			||||||
 | 
					from documents.models import CustomFieldInstance
 | 
				
			||||||
from documents.models import Document
 | 
					from documents.models import Document
 | 
				
			||||||
from documents.models import DocumentType
 | 
					from documents.models import DocumentType
 | 
				
			||||||
from documents.models import StoragePath
 | 
					from documents.models import StoragePath
 | 
				
			||||||
from documents.models import Tag
 | 
					from documents.models import Tag
 | 
				
			||||||
 | 
					from documents.models import Workflow
 | 
				
			||||||
 | 
					from documents.models import WorkflowRun
 | 
				
			||||||
 | 
					from documents.models import WorkflowTrigger
 | 
				
			||||||
from documents.parsers import DocumentParser
 | 
					from documents.parsers import DocumentParser
 | 
				
			||||||
from documents.parsers import get_parser_class_for_mime_type
 | 
					from documents.parsers import get_parser_class_for_mime_type
 | 
				
			||||||
from documents.plugins.base import ConsumeTaskPlugin
 | 
					from documents.plugins.base import ConsumeTaskPlugin
 | 
				
			||||||
@ -44,6 +48,7 @@ from documents.plugins.helpers import ProgressStatusOptions
 | 
				
			|||||||
from documents.sanity_checker import SanityCheckFailedException
 | 
					from documents.sanity_checker import SanityCheckFailedException
 | 
				
			||||||
from documents.signals import document_updated
 | 
					from documents.signals import document_updated
 | 
				
			||||||
from documents.signals.handlers import cleanup_document_deletion
 | 
					from documents.signals.handlers import cleanup_document_deletion
 | 
				
			||||||
 | 
					from documents.signals.handlers import run_workflows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if settings.AUDIT_LOG_ENABLED:
 | 
					if settings.AUDIT_LOG_ENABLED:
 | 
				
			||||||
    from auditlog.models import LogEntry
 | 
					    from auditlog.models import LogEntry
 | 
				
			||||||
@ -337,3 +342,81 @@ def empty_trash(doc_ids=None):
 | 
				
			|||||||
            cleanup_document_deletion,
 | 
					            cleanup_document_deletion,
 | 
				
			||||||
            sender=Document,
 | 
					            sender=Document,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@shared_task
 | 
				
			||||||
 | 
					def check_scheduled_workflows():
 | 
				
			||||||
 | 
					    scheduled_workflows: list[Workflow] = Workflow.objects.filter(
 | 
				
			||||||
 | 
					        triggers__type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					        enabled=True,
 | 
				
			||||||
 | 
					    ).prefetch_related("triggers")
 | 
				
			||||||
 | 
					    if scheduled_workflows.count() > 0:
 | 
				
			||||||
 | 
					        logger.debug(f"Checking {len(scheduled_workflows)} scheduled workflows")
 | 
				
			||||||
 | 
					        for workflow in scheduled_workflows:
 | 
				
			||||||
 | 
					            schedule_triggers = workflow.triggers.filter(
 | 
				
			||||||
 | 
					                type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            trigger: WorkflowTrigger
 | 
				
			||||||
 | 
					            for trigger in schedule_triggers:
 | 
				
			||||||
 | 
					                documents = Document.objects.none()
 | 
				
			||||||
 | 
					                offset_td = timedelta(days=trigger.schedule_offset_days)
 | 
				
			||||||
 | 
					                logger.debug(
 | 
				
			||||||
 | 
					                    f"Checking trigger {trigger} with offset {offset_td} against field: {trigger.schedule_date_field}",
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                match trigger.schedule_date_field:
 | 
				
			||||||
 | 
					                    case WorkflowTrigger.ScheduleDateField.ADDED:
 | 
				
			||||||
 | 
					                        documents = Document.objects.filter(
 | 
				
			||||||
 | 
					                            added__lt=timezone.now() - offset_td,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    case WorkflowTrigger.ScheduleDateField.CREATED:
 | 
				
			||||||
 | 
					                        documents = Document.objects.filter(
 | 
				
			||||||
 | 
					                            created__lt=timezone.now() - offset_td,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    case WorkflowTrigger.ScheduleDateField.MODIFIED:
 | 
				
			||||||
 | 
					                        documents = Document.objects.filter(
 | 
				
			||||||
 | 
					                            modified__lt=timezone.now() - offset_td,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    case WorkflowTrigger.ScheduleDateField.CUSTOM_FIELD:
 | 
				
			||||||
 | 
					                        cf_instances = CustomFieldInstance.objects.filter(
 | 
				
			||||||
 | 
					                            field=trigger.schedule_date_custom_field,
 | 
				
			||||||
 | 
					                            value_date__lt=timezone.now() - offset_td,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                        documents = Document.objects.filter(
 | 
				
			||||||
 | 
					                            id__in=cf_instances.values_list("document", flat=True),
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                if documents.count() > 0:
 | 
				
			||||||
 | 
					                    logger.debug(
 | 
				
			||||||
 | 
					                        f"Found {documents.count()} documents for trigger {trigger}",
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    for document in documents:
 | 
				
			||||||
 | 
					                        workflow_runs = WorkflowRun.objects.filter(
 | 
				
			||||||
 | 
					                            document=document,
 | 
				
			||||||
 | 
					                            type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					                            workflow=workflow,
 | 
				
			||||||
 | 
					                        ).order_by("-run_at")
 | 
				
			||||||
 | 
					                        if not trigger.schedule_is_recurring and workflow_runs.exists():
 | 
				
			||||||
 | 
					                            # schedule is non-recurring and the workflow has already been run
 | 
				
			||||||
 | 
					                            logger.debug(
 | 
				
			||||||
 | 
					                                f"Skipping document {document} for non-recurring workflow {workflow} as it has already been run",
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                            continue
 | 
				
			||||||
 | 
					                        elif (
 | 
				
			||||||
 | 
					                            trigger.schedule_is_recurring
 | 
				
			||||||
 | 
					                            and workflow_runs.exists()
 | 
				
			||||||
 | 
					                            and (
 | 
				
			||||||
 | 
					                                workflow_runs.last().run_at
 | 
				
			||||||
 | 
					                                > timezone.now()
 | 
				
			||||||
 | 
					                                - timedelta(
 | 
				
			||||||
 | 
					                                    days=trigger.schedule_recurring_interval_days,
 | 
				
			||||||
 | 
					                                )
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        ):
 | 
				
			||||||
 | 
					                            # schedule is recurring but the last run was within the number of recurring interval days
 | 
				
			||||||
 | 
					                            logger.debug(
 | 
				
			||||||
 | 
					                                f"Skipping document {document} for recurring workflow {workflow} as the last run was within the recurring interval",
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                            continue
 | 
				
			||||||
 | 
					                        run_workflows(
 | 
				
			||||||
 | 
					                            WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					                            document,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,7 @@ from documents.models import StoragePath
 | 
				
			|||||||
from documents.models import Tag
 | 
					from documents.models import Tag
 | 
				
			||||||
from documents.models import Workflow
 | 
					from documents.models import Workflow
 | 
				
			||||||
from documents.models import WorkflowAction
 | 
					from documents.models import WorkflowAction
 | 
				
			||||||
 | 
					from documents.models import WorkflowRun
 | 
				
			||||||
from documents.models import WorkflowTrigger
 | 
					from documents.models import WorkflowTrigger
 | 
				
			||||||
from documents.signals import document_consumption_finished
 | 
					from documents.signals import document_consumption_finished
 | 
				
			||||||
from documents.tests.utils import DirectoriesMixin
 | 
					from documents.tests.utils import DirectoriesMixin
 | 
				
			||||||
@ -1306,6 +1307,275 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, APITestCase):
 | 
				
			|||||||
        # group2 should have been added
 | 
					        # group2 should have been added
 | 
				
			||||||
        self.assertIn(self.group2, group_perms)
 | 
					        self.assertIn(self.group2, group_perms)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_workflow_scheduled_trigger_created(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        GIVEN:
 | 
				
			||||||
 | 
					            - Existing workflow with SCHEDULED trigger against the created field and action that assigns owner
 | 
				
			||||||
 | 
					            - Existing doc that matches the trigger
 | 
				
			||||||
 | 
					        WHEN:
 | 
				
			||||||
 | 
					            - Scheduled workflows are checked
 | 
				
			||||||
 | 
					        THEN:
 | 
				
			||||||
 | 
					            - Workflow runs, document owner is updated
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        trigger = WorkflowTrigger.objects.create(
 | 
				
			||||||
 | 
					            type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					            schedule_offset_days=1,
 | 
				
			||||||
 | 
					            schedule_date_field="created",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        action = WorkflowAction.objects.create(
 | 
				
			||||||
 | 
					            assign_title="Doc assign owner",
 | 
				
			||||||
 | 
					            assign_owner=self.user2,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w = Workflow.objects.create(
 | 
				
			||||||
 | 
					            name="Workflow 1",
 | 
				
			||||||
 | 
					            order=0,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w.triggers.add(trigger)
 | 
				
			||||||
 | 
					        w.actions.add(action)
 | 
				
			||||||
 | 
					        w.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        now = timezone.localtime(timezone.now())
 | 
				
			||||||
 | 
					        created = now - timedelta(weeks=520)
 | 
				
			||||||
 | 
					        doc = Document.objects.create(
 | 
				
			||||||
 | 
					            title="sample test",
 | 
				
			||||||
 | 
					            correspondent=self.c,
 | 
				
			||||||
 | 
					            original_filename="sample.pdf",
 | 
				
			||||||
 | 
					            created=created,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tasks.check_scheduled_workflows()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        doc.refresh_from_db()
 | 
				
			||||||
 | 
					        self.assertEqual(doc.owner, self.user2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_workflow_scheduled_trigger_added(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        GIVEN:
 | 
				
			||||||
 | 
					            - Existing workflow with SCHEDULED trigger against the added field and action that assigns owner
 | 
				
			||||||
 | 
					            - Existing doc that matches the trigger
 | 
				
			||||||
 | 
					        WHEN:
 | 
				
			||||||
 | 
					            - Scheduled workflows are checked
 | 
				
			||||||
 | 
					        THEN:
 | 
				
			||||||
 | 
					            - Workflow runs, document owner is updated
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        trigger = WorkflowTrigger.objects.create(
 | 
				
			||||||
 | 
					            type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					            schedule_offset_days=1,
 | 
				
			||||||
 | 
					            schedule_date_field=WorkflowTrigger.ScheduleDateField.ADDED,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        action = WorkflowAction.objects.create(
 | 
				
			||||||
 | 
					            assign_title="Doc assign owner",
 | 
				
			||||||
 | 
					            assign_owner=self.user2,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w = Workflow.objects.create(
 | 
				
			||||||
 | 
					            name="Workflow 1",
 | 
				
			||||||
 | 
					            order=0,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w.triggers.add(trigger)
 | 
				
			||||||
 | 
					        w.actions.add(action)
 | 
				
			||||||
 | 
					        w.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        added = timezone.now() - timedelta(days=365)
 | 
				
			||||||
 | 
					        doc = Document.objects.create(
 | 
				
			||||||
 | 
					            title="sample test",
 | 
				
			||||||
 | 
					            correspondent=self.c,
 | 
				
			||||||
 | 
					            original_filename="sample.pdf",
 | 
				
			||||||
 | 
					            added=added,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tasks.check_scheduled_workflows()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        doc.refresh_from_db()
 | 
				
			||||||
 | 
					        self.assertEqual(doc.owner, self.user2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @mock.patch("documents.models.Document.objects.filter", autospec=True)
 | 
				
			||||||
 | 
					    def test_workflow_scheduled_trigger_modified(self, mock_filter):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        GIVEN:
 | 
				
			||||||
 | 
					            - Existing workflow with SCHEDULED trigger against the modified field and action that assigns owner
 | 
				
			||||||
 | 
					            - Existing doc that matches the trigger
 | 
				
			||||||
 | 
					        WHEN:
 | 
				
			||||||
 | 
					            - Scheduled workflows are checked
 | 
				
			||||||
 | 
					        THEN:
 | 
				
			||||||
 | 
					            - Workflow runs, document owner is updated
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        # we have to mock because modified field is auto_now
 | 
				
			||||||
 | 
					        mock_filter.return_value = Document.objects.all()
 | 
				
			||||||
 | 
					        trigger = WorkflowTrigger.objects.create(
 | 
				
			||||||
 | 
					            type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					            schedule_offset_days=1,
 | 
				
			||||||
 | 
					            schedule_date_field=WorkflowTrigger.ScheduleDateField.MODIFIED,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        action = WorkflowAction.objects.create(
 | 
				
			||||||
 | 
					            assign_title="Doc assign owner",
 | 
				
			||||||
 | 
					            assign_owner=self.user2,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w = Workflow.objects.create(
 | 
				
			||||||
 | 
					            name="Workflow 1",
 | 
				
			||||||
 | 
					            order=0,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w.triggers.add(trigger)
 | 
				
			||||||
 | 
					        w.actions.add(action)
 | 
				
			||||||
 | 
					        w.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        doc = Document.objects.create(
 | 
				
			||||||
 | 
					            title="sample test",
 | 
				
			||||||
 | 
					            correspondent=self.c,
 | 
				
			||||||
 | 
					            original_filename="sample.pdf",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tasks.check_scheduled_workflows()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        doc.refresh_from_db()
 | 
				
			||||||
 | 
					        self.assertEqual(doc.owner, self.user2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_workflow_scheduled_trigger_custom_field(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        GIVEN:
 | 
				
			||||||
 | 
					            - Existing workflow with SCHEDULED trigger against a custom field and action that assigns owner
 | 
				
			||||||
 | 
					            - Existing doc that matches the trigger
 | 
				
			||||||
 | 
					        WHEN:
 | 
				
			||||||
 | 
					            - Scheduled workflows are checked
 | 
				
			||||||
 | 
					        THEN:
 | 
				
			||||||
 | 
					            - Workflow runs, document owner is updated
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        trigger = WorkflowTrigger.objects.create(
 | 
				
			||||||
 | 
					            type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					            schedule_offset_days=1,
 | 
				
			||||||
 | 
					            schedule_date_field=WorkflowTrigger.ScheduleDateField.CUSTOM_FIELD,
 | 
				
			||||||
 | 
					            schedule_date_custom_field=self.cf1,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        action = WorkflowAction.objects.create(
 | 
				
			||||||
 | 
					            assign_title="Doc assign owner",
 | 
				
			||||||
 | 
					            assign_owner=self.user2,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w = Workflow.objects.create(
 | 
				
			||||||
 | 
					            name="Workflow 1",
 | 
				
			||||||
 | 
					            order=0,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w.triggers.add(trigger)
 | 
				
			||||||
 | 
					        w.actions.add(action)
 | 
				
			||||||
 | 
					        w.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        doc = Document.objects.create(
 | 
				
			||||||
 | 
					            title="sample test",
 | 
				
			||||||
 | 
					            correspondent=self.c,
 | 
				
			||||||
 | 
					            original_filename="sample.pdf",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        CustomFieldInstance.objects.create(
 | 
				
			||||||
 | 
					            document=doc,
 | 
				
			||||||
 | 
					            field=self.cf1,
 | 
				
			||||||
 | 
					            value_date=timezone.now() - timedelta(days=2),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tasks.check_scheduled_workflows()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        doc.refresh_from_db()
 | 
				
			||||||
 | 
					        self.assertEqual(doc.owner, self.user2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_workflow_scheduled_already_run(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        GIVEN:
 | 
				
			||||||
 | 
					            - Existing workflow with SCHEDULED trigger
 | 
				
			||||||
 | 
					            - Existing doc that has already had the workflow run
 | 
				
			||||||
 | 
					        WHEN:
 | 
				
			||||||
 | 
					            - Scheduled workflows are checked
 | 
				
			||||||
 | 
					        THEN:
 | 
				
			||||||
 | 
					            - Workflow does not run again
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        trigger = WorkflowTrigger.objects.create(
 | 
				
			||||||
 | 
					            type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					            schedule_offset_days=1,
 | 
				
			||||||
 | 
					            schedule_date_field=WorkflowTrigger.ScheduleDateField.CREATED,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        action = WorkflowAction.objects.create(
 | 
				
			||||||
 | 
					            assign_title="Doc assign owner",
 | 
				
			||||||
 | 
					            assign_owner=self.user2,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w = Workflow.objects.create(
 | 
				
			||||||
 | 
					            name="Workflow 1",
 | 
				
			||||||
 | 
					            order=0,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w.triggers.add(trigger)
 | 
				
			||||||
 | 
					        w.actions.add(action)
 | 
				
			||||||
 | 
					        w.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        doc = Document.objects.create(
 | 
				
			||||||
 | 
					            title="sample test",
 | 
				
			||||||
 | 
					            correspondent=self.c,
 | 
				
			||||||
 | 
					            original_filename="sample.pdf",
 | 
				
			||||||
 | 
					            created=timezone.now() - timedelta(days=2),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wr = WorkflowRun.objects.create(
 | 
				
			||||||
 | 
					            workflow=w,
 | 
				
			||||||
 | 
					            document=doc,
 | 
				
			||||||
 | 
					            type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					            run_at=timezone.now(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            str(wr),
 | 
				
			||||||
 | 
					            f"WorkflowRun of {w} at {wr.run_at} on {doc}",
 | 
				
			||||||
 | 
					        )  # coverage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tasks.check_scheduled_workflows()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        doc.refresh_from_db()
 | 
				
			||||||
 | 
					        self.assertIsNone(doc.owner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_workflow_scheduled_trigger_too_early(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        GIVEN:
 | 
				
			||||||
 | 
					            - Existing workflow with SCHEDULED trigger and recurring interval of 7 days
 | 
				
			||||||
 | 
					            - Workflow run date is 6 days ago
 | 
				
			||||||
 | 
					        WHEN:
 | 
				
			||||||
 | 
					            - Scheduled workflows are checked
 | 
				
			||||||
 | 
					        THEN:
 | 
				
			||||||
 | 
					            - Workflow does not run as the offset is not met
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        trigger = WorkflowTrigger.objects.create(
 | 
				
			||||||
 | 
					            type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					            schedule_offset_days=30,
 | 
				
			||||||
 | 
					            schedule_date_field=WorkflowTrigger.ScheduleDateField.CREATED,
 | 
				
			||||||
 | 
					            schedule_is_recurring=True,
 | 
				
			||||||
 | 
					            schedule_recurring_interval_days=7,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        action = WorkflowAction.objects.create(
 | 
				
			||||||
 | 
					            assign_title="Doc assign owner",
 | 
				
			||||||
 | 
					            assign_owner=self.user2,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w = Workflow.objects.create(
 | 
				
			||||||
 | 
					            name="Workflow 1",
 | 
				
			||||||
 | 
					            order=0,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        w.triggers.add(trigger)
 | 
				
			||||||
 | 
					        w.actions.add(action)
 | 
				
			||||||
 | 
					        w.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        doc = Document.objects.create(
 | 
				
			||||||
 | 
					            title="sample test",
 | 
				
			||||||
 | 
					            correspondent=self.c,
 | 
				
			||||||
 | 
					            original_filename="sample.pdf",
 | 
				
			||||||
 | 
					            created=timezone.now() - timedelta(days=40),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        WorkflowRun.objects.create(
 | 
				
			||||||
 | 
					            workflow=w,
 | 
				
			||||||
 | 
					            document=doc,
 | 
				
			||||||
 | 
					            type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
 | 
				
			||||||
 | 
					            run_at=timezone.now() - timedelta(days=6),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertLogs(level="DEBUG") as cm:
 | 
				
			||||||
 | 
					            tasks.check_scheduled_workflows()
 | 
				
			||||||
 | 
					            self.assertIn(
 | 
				
			||||||
 | 
					                "last run was within the recurring interval",
 | 
				
			||||||
 | 
					                " ".join(cm.output),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            doc.refresh_from_db()
 | 
				
			||||||
 | 
					            self.assertIsNone(doc.owner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_workflow_enabled_disabled(self):
 | 
					    def test_workflow_enabled_disabled(self):
 | 
				
			||||||
        trigger = WorkflowTrigger.objects.create(
 | 
					        trigger = WorkflowTrigger.objects.create(
 | 
				
			||||||
            type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED,
 | 
					            type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED,
 | 
				
			||||||
@ -1354,7 +1624,7 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, APITestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def test_new_trigger_type_raises_exception(self):
 | 
					    def test_new_trigger_type_raises_exception(self):
 | 
				
			||||||
        trigger = WorkflowTrigger.objects.create(
 | 
					        trigger = WorkflowTrigger.objects.create(
 | 
				
			||||||
            type=4,
 | 
					            type=99,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        action = WorkflowAction.objects.create(
 | 
					        action = WorkflowAction.objects.create(
 | 
				
			||||||
            assign_title="Doc assign owner",
 | 
					            assign_title="Doc assign owner",
 | 
				
			||||||
@ -1370,7 +1640,7 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, APITestCase):
 | 
				
			|||||||
        doc = Document.objects.create(
 | 
					        doc = Document.objects.create(
 | 
				
			||||||
            title="test",
 | 
					            title="test",
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertRaises(Exception, document_matches_workflow, doc, w, 4)
 | 
					        self.assertRaises(Exception, document_matches_workflow, doc, w, 99)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_removal_action_document_updated_workflow(self):
 | 
					    def test_removal_action_document_updated_workflow(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
				
			|||||||
@ -216,6 +216,17 @@ def _parse_beat_schedule() -> dict:
 | 
				
			|||||||
                "expires": 23.0 * 60.0 * 60.0,
 | 
					                "expires": 23.0 * 60.0 * 60.0,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "Check and run scheduled workflows",
 | 
				
			||||||
 | 
					            "env_key": "PAPERLESS_WORKFLOW_SCHEDULED_TASK_CRON",
 | 
				
			||||||
 | 
					            # Default hourly at 5 minutes past the hour
 | 
				
			||||||
 | 
					            "env_default": "5 */1 * * *",
 | 
				
			||||||
 | 
					            "task": "documents.tasks.check_scheduled_workflows",
 | 
				
			||||||
 | 
					            "options": {
 | 
				
			||||||
 | 
					                # 1 minute before default schedule sends again
 | 
				
			||||||
 | 
					                "expires": 59.0 * 60.0,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    for task in tasks:
 | 
					    for task in tasks:
 | 
				
			||||||
        # Either get the environment setting or use the default
 | 
					        # Either get the environment setting or use the default
 | 
				
			||||||
 | 
				
			|||||||
@ -157,6 +157,7 @@ class TestCeleryScheduleParsing(TestCase):
 | 
				
			|||||||
    INDEX_EXPIRE_TIME = 23.0 * 60.0 * 60.0
 | 
					    INDEX_EXPIRE_TIME = 23.0 * 60.0 * 60.0
 | 
				
			||||||
    SANITY_EXPIRE_TIME = ((7.0 * 24.0) - 1.0) * 60.0 * 60.0
 | 
					    SANITY_EXPIRE_TIME = ((7.0 * 24.0) - 1.0) * 60.0 * 60.0
 | 
				
			||||||
    EMPTY_TRASH_EXPIRE_TIME = 23.0 * 60.0 * 60.0
 | 
					    EMPTY_TRASH_EXPIRE_TIME = 23.0 * 60.0 * 60.0
 | 
				
			||||||
 | 
					    RUN_SCHEDULED_WORKFLOWS_EXPIRE_TIME = 59.0 * 60.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_schedule_configuration_default(self):
 | 
					    def test_schedule_configuration_default(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@ -196,6 +197,11 @@ class TestCeleryScheduleParsing(TestCase):
 | 
				
			|||||||
                    "schedule": crontab(minute=0, hour="1"),
 | 
					                    "schedule": crontab(minute=0, hour="1"),
 | 
				
			||||||
                    "options": {"expires": self.EMPTY_TRASH_EXPIRE_TIME},
 | 
					                    "options": {"expires": self.EMPTY_TRASH_EXPIRE_TIME},
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                "Check and run scheduled workflows": {
 | 
				
			||||||
 | 
					                    "task": "documents.tasks.check_scheduled_workflows",
 | 
				
			||||||
 | 
					                    "schedule": crontab(minute="5", hour="*/1"),
 | 
				
			||||||
 | 
					                    "options": {"expires": self.RUN_SCHEDULED_WORKFLOWS_EXPIRE_TIME},
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            schedule,
 | 
					            schedule,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@ -243,6 +249,11 @@ class TestCeleryScheduleParsing(TestCase):
 | 
				
			|||||||
                    "schedule": crontab(minute=0, hour="1"),
 | 
					                    "schedule": crontab(minute=0, hour="1"),
 | 
				
			||||||
                    "options": {"expires": self.EMPTY_TRASH_EXPIRE_TIME},
 | 
					                    "options": {"expires": self.EMPTY_TRASH_EXPIRE_TIME},
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                "Check and run scheduled workflows": {
 | 
				
			||||||
 | 
					                    "task": "documents.tasks.check_scheduled_workflows",
 | 
				
			||||||
 | 
					                    "schedule": crontab(minute="5", hour="*/1"),
 | 
				
			||||||
 | 
					                    "options": {"expires": self.RUN_SCHEDULED_WORKFLOWS_EXPIRE_TIME},
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            schedule,
 | 
					            schedule,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@ -282,6 +293,11 @@ class TestCeleryScheduleParsing(TestCase):
 | 
				
			|||||||
                    "schedule": crontab(minute=0, hour="1"),
 | 
					                    "schedule": crontab(minute=0, hour="1"),
 | 
				
			||||||
                    "options": {"expires": self.EMPTY_TRASH_EXPIRE_TIME},
 | 
					                    "options": {"expires": self.EMPTY_TRASH_EXPIRE_TIME},
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                "Check and run scheduled workflows": {
 | 
				
			||||||
 | 
					                    "task": "documents.tasks.check_scheduled_workflows",
 | 
				
			||||||
 | 
					                    "schedule": crontab(minute="5", hour="*/1"),
 | 
				
			||||||
 | 
					                    "options": {"expires": self.RUN_SCHEDULED_WORKFLOWS_EXPIRE_TIME},
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            schedule,
 | 
					            schedule,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@ -303,6 +319,7 @@ class TestCeleryScheduleParsing(TestCase):
 | 
				
			|||||||
                "PAPERLESS_SANITY_TASK_CRON": "disable",
 | 
					                "PAPERLESS_SANITY_TASK_CRON": "disable",
 | 
				
			||||||
                "PAPERLESS_INDEX_TASK_CRON": "disable",
 | 
					                "PAPERLESS_INDEX_TASK_CRON": "disable",
 | 
				
			||||||
                "PAPERLESS_EMPTY_TRASH_TASK_CRON": "disable",
 | 
					                "PAPERLESS_EMPTY_TRASH_TASK_CRON": "disable",
 | 
				
			||||||
 | 
					                "PAPERLESS_WORKFLOW_SCHEDULED_TASK_CRON": "disable",
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            schedule = _parse_beat_schedule()
 | 
					            schedule = _parse_beat_schedule()
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user