diff --git a/dokuly/documents/views.py b/dokuly/documents/views.py index 5f9fcc1..fffcbec 100644 --- a/dokuly/documents/views.py +++ b/dokuly/documents/views.py @@ -8,6 +8,7 @@ import os import shutil +from organizations.models import Organization as OrgModel from organizations.revision_utils import build_full_document_number from organizations.revision_utils import increment_revision_counters, build_formatted_revision from part_numbers.methods import get_next_part_number @@ -231,6 +232,12 @@ def create_new_document(request, **kwargs): document.save() + try: + _org = OrgModel.objects.get(id=organization_id) + doc_revision_format = _org.document_revision_format + except Exception: + doc_revision_format = "major-only" + document.formatted_revision = build_formatted_revision( organization_id=organization_id, prefix=prefix.prefix, @@ -238,7 +245,8 @@ def create_new_document(request, **kwargs): revision_count_major=document.revision_count_major, revision_count_minor=document.revision_count_minor, project_number=document.project.full_project_number if document.project else None, - created_at=document.created_at + created_at=document.created_at, + revision_format=doc_revision_format, ) # Use template-based document number generation @@ -996,6 +1004,12 @@ def auto_new_revision(request, pk, **kwargs): prefix = Document_Prefix.objects.get(pk=old_revision.prefix_id) if old_revision.prefix_id and old_revision.prefix_id != -1 else None prefix_str = prefix.prefix if prefix else "" + try: + _org = OrgModel.objects.get(id=organization_id) + doc_revision_format = _org.document_revision_format + except Exception: + doc_revision_format = "major-only" + new_revision.formatted_revision = build_formatted_revision( organization_id=organization_id, prefix=prefix_str, @@ -1003,7 +1017,8 @@ def auto_new_revision(request, pk, **kwargs): revision_count_major=new_revision.revision_count_major, revision_count_minor=new_revision.revision_count_minor, project_number=new_revision.project.full_project_number if new_revision.project else None, - created_at=new_revision.created_at + created_at=new_revision.created_at, + revision_format=doc_revision_format, ) # Use template-based document number generation diff --git a/dokuly/frontend/src/components/admin/adminComponents/documents/documentNumberSettings.js b/dokuly/frontend/src/components/admin/adminComponents/documents/documentNumberSettings.js index 6386f1e..afa4517 100644 --- a/dokuly/frontend/src/components/admin/adminComponents/documents/documentNumberSettings.js +++ b/dokuly/frontend/src/components/admin/adminComponents/documents/documentNumberSettings.js @@ -43,6 +43,7 @@ const DocumentNumberSettings = ({ org, setRefresh }) => { template: fullDocumentNumberTemplate, use_number_revisions: useNumberRevisions, start_major_revision_at_one: revisionStartAtOne, + revision_format: revisionFormat, }); if (response.status === 200) { diff --git a/dokuly/frontend/src/components/admin/adminComponents/general/revisionSystemSettings.js b/dokuly/frontend/src/components/admin/adminComponents/general/revisionSystemSettings.js index f0f33f4..88e44b7 100644 --- a/dokuly/frontend/src/components/admin/adminComponents/general/revisionSystemSettings.js +++ b/dokuly/frontend/src/components/admin/adminComponents/general/revisionSystemSettings.js @@ -1,6 +1,10 @@ import React, { useState, useEffect } from "react"; import { Form, Row, Col, Dropdown } from "react-bootstrap"; -import { editOrg, previewPartNumberTemplate, previewFormattedRevisionTemplate } from "../../functions/queries"; +import { + editOrg, + previewPartNumberTemplate, + previewFormattedRevisionTemplate, +} from "../../functions/queries"; import { toast } from "react-toastify"; import SubmitButton from "../../../dokuly_components/submitButton"; import CheckBox from "../../../dokuly_components/checkBox"; @@ -9,33 +13,38 @@ import QuestionToolTip from "../../../dokuly_components/questionToolTip"; const RevisionSystemSettings = ({ org, setRefresh }) => { const [useNumberRevisions, setUseNumberRevisions] = useState( - org?.use_number_revisions || false + org?.use_number_revisions || false, ); const [revisionFormat, setRevisionFormat] = useState( - org?.revision_format || "major-minor" + org?.revision_format || "major-minor", ); const [revisionStartAtOne, setRevisionStartAtOne] = useState( - org?.start_major_revision_at_one || false + org?.start_major_revision_at_one || false, ); const [fullPartNumberTemplate, setFullPartNumberTemplate] = useState( - org?.full_part_number_template || "" + org?.full_part_number_template || "", ); const [formattedRevisionTemplate, setFormattedRevisionTemplate] = useState( - org?.formatted_revision_template || "" + org?.formatted_revision_template || "", ); const [isUpdating, setIsUpdating] = useState(false); const [previewExamples, setPreviewExamples] = useState([]); const [isLoadingPreview, setIsLoadingPreview] = useState(false); const [revisionPreviewExamples, setRevisionPreviewExamples] = useState([]); - const [isLoadingRevisionPreview, setIsLoadingRevisionPreview] = useState(false); + const [isLoadingRevisionPreview, setIsLoadingRevisionPreview] = + useState(false); // Update state when org prop changes useEffect(() => { if (org) { setUseNumberRevisions(org.use_number_revisions || false); setRevisionFormat(org.revision_format || "major-minor"); - setFullPartNumberTemplate(org.full_part_number_template || ""); - setFormattedRevisionTemplate(org.formatted_revision_template || ""); + setFullPartNumberTemplate( + org.full_part_number_template || "", + ); + setFormattedRevisionTemplate( + org.formatted_revision_template || "", + ); setRevisionStartAtOne(org.start_major_revision_at_one || false); } }, [org]); @@ -49,13 +58,14 @@ const RevisionSystemSettings = ({ org, setRefresh }) => { template: fullPartNumberTemplate, use_number_revisions: useNumberRevisions, start_major_revision_at_one: revisionStartAtOne, + revision_format: revisionFormat, }); - + if (response.status === 200) { setPreviewExamples(response.data.examples || []); } } catch (error) { - console.error('Error fetching template preview:', error); + console.error("Error fetching template preview:", error); setPreviewExamples([]); } finally { setIsLoadingPreview(false); @@ -65,7 +75,12 @@ const RevisionSystemSettings = ({ org, setRefresh }) => { // Debounce the preview fetch const timeoutId = setTimeout(fetchPreview, 300); return () => clearTimeout(timeoutId); - }, [fullPartNumberTemplate, useNumberRevisions, revisionStartAtOne]); + }, [ + fullPartNumberTemplate, + useNumberRevisions, + revisionStartAtOne, + revisionFormat, + ]); // Fetch formatted revision preview from backend whenever settings change useEffect(() => { @@ -78,12 +93,12 @@ const RevisionSystemSettings = ({ org, setRefresh }) => { revision_format: revisionFormat, start_major_revision_at_one: revisionStartAtOne, }); - + if (response.status === 200) { setRevisionPreviewExamples(response.data.examples || []); } } catch (error) { - console.error('Error fetching revision template preview:', error); + console.error("Error fetching revision template preview:", error); setRevisionPreviewExamples([]); } finally { setIsLoadingRevisionPreview(false); @@ -93,7 +108,12 @@ const RevisionSystemSettings = ({ org, setRefresh }) => { // Debounce the preview fetch const timeoutId = setTimeout(fetchRevisionPreview, 300); return () => clearTimeout(timeoutId); - }, [formattedRevisionTemplate, useNumberRevisions, revisionFormat, revisionStartAtOne]); + }, [ + formattedRevisionTemplate, + useNumberRevisions, + revisionFormat, + revisionStartAtOne, + ]); const handleSave = async () => { setIsUpdating(true); @@ -107,11 +127,11 @@ const RevisionSystemSettings = ({ org, setRefresh }) => { }; const response = await editOrg(org.id, data); - + if (response.status === 200) { toast.success("Revision system settings updated successfully."); setRefresh(true); - + // Don't auto-check for corrupted revisions after saving } else { toast.error("Failed to update revision system settings."); @@ -127,52 +147,70 @@ const RevisionSystemSettings = ({ org, setRefresh }) => { const handleReset = () => { setUseNumberRevisions(org?.use_number_revisions || false); setRevisionFormat(org?.revision_format || "major-minor"); - setFullPartNumberTemplate(org?.full_part_number_template || ""); - setFormattedRevisionTemplate(org?.formatted_revision_template || ""); + setFullPartNumberTemplate( + org?.full_part_number_template || "", + ); + setFormattedRevisionTemplate( + org?.formatted_revision_template || "", + ); setRevisionStartAtOne(org?.start_major_revision_at_one || false); }; - const hasChanges = + const hasChanges = useNumberRevisions !== (org?.use_number_revisions || false) || revisionFormat !== (org?.revision_format || "major-minor") || - fullPartNumberTemplate !== (org?.full_part_number_template || "") || - formattedRevisionTemplate !== (org?.formatted_revision_template || "") || + fullPartNumberTemplate !== + (org?.full_part_number_template || "") || + formattedRevisionTemplate !== + (org?.formatted_revision_template || "") || revisionStartAtOne !== (org?.start_major_revision_at_one || false); // Available template keywords const availableKeywords = [ - { keyword: '', description: 'Part type (PRT, ASM, PCBA)' }, - { keyword: '', description: 'Numeric part number' }, - { keyword: '', description: 'Major revision (A, B, C or 0, 1, 2)' }, - { keyword: '', description: 'Minor revision (A, B, C or 0, 1, 2)' }, - { keyword: '', description: 'Major Revision (A, B, C or 0, 1, 2)' }, - { keyword: '', description: 'Project number (if applicable)' }, - { keyword: '', description: 'Day of creation (01-31)' }, - { keyword: '', description: 'Month of creation (01-12)' }, - { keyword: '', description: 'Year of creation (e.g., 2025)' }, + { keyword: "", description: "Part type (PRT, ASM, PCBA)" }, + { keyword: "", description: "Numeric part number" }, + { + keyword: "", + description: "Major revision (A, B, C or 0, 1, 2)", + }, + { + keyword: "", + description: "Minor revision (A, B, C or 0, 1, 2)", + }, + { + keyword: "", + description: "Major Revision (A, B, C or 0, 1, 2)", + }, + { + keyword: "", + description: "Project number (if applicable)", + }, + { keyword: "", description: "Day of creation (01-31)" }, + { keyword: "", description: "Month of creation (01-12)" }, + { keyword: "", description: "Year of creation (e.g., 2025)" }, ]; // Helper function to render template with highlighted keywords const renderTemplateWithHighlights = (template) => { if (!template) return null; - - const keywords = availableKeywords.map(k => k.keyword); + + const keywords = availableKeywords.map((k) => k.keyword); const parts = []; let lastIndex = 0; - + // Find all keyword matches and their positions const matches = []; - keywords.forEach(keyword => { + keywords.forEach((keyword) => { let index = template.indexOf(keyword); while (index !== -1) { matches.push({ keyword, index }); index = template.indexOf(keyword, index + 1); } }); - + // Sort matches by position matches.sort((a, b) => a.index - b.index); - + // Build the rendered output matches.forEach(({ keyword, index }) => { // Add text before the keyword @@ -180,40 +218,40 @@ const RevisionSystemSettings = ({ org, setRefresh }) => { parts.push( {template.substring(lastIndex, index)} - + , ); } - + // Add the highlighted keyword parts.push( {keyword} - + , ); - + lastIndex = index + keyword.length; }); - + // Add remaining text if (lastIndex < template.length) { parts.push( - - {template.substring(lastIndex)} - + {template.substring(lastIndex)}, ); } - - return
{parts}
; + + return ( +
{parts}
+ ); }; return ( @@ -222,272 +260,324 @@ const RevisionSystemSettings = ({ org, setRefresh }) => { Revision System Settings

- Configure how revisions are displayed and managed for parts, assemblies, PCBAs, and documents. - Use the template to control the exact formatting including separators. + Configure how revisions are displayed and managed for parts, assemblies, + PCBAs, and documents. Use the template to control the exact formatting + including separators.

- -
+ + + + + + setUseNumberRevisions(e.target.checked)} + /> + + When enabled, revisions will use numbers instead of letters. By + default, number revisions start at 0 (0, 1, 2...), but you can + configure them to start at 1 using the setting below. + + + + + + {useNumberRevisions && ( setUseNumberRevisions(e.target.checked)} + id="revision-start-at-one" + label="Start major revisions at 1" + checked={revisionStartAtOne} + onChange={(e) => setRevisionStartAtOne(e.target.checked)} /> - When enabled, revisions will use numbers instead of letters. By default, number revisions start at 0 (0, 1, 2...), but you can configure them to start at 1 using the setting below. + When enabled, major revisions will display starting at 1 + instead of 0 (e.g., 1, 2, 3... instead of 0, 1, 2...). Minor + revisions always start at 0 regardless of this setting (e.g., + 1-0, 1-1, 1-2, 2-0...). This only affects how revisions are + displayed, not how they are stored in the database. + )} - {useNumberRevisions && ( - - - - setRevisionStartAtOne(e.target.checked)} - /> - - When enabled, major revisions will display starting at 1 instead of 0 (e.g., 1, 2, 3... instead of 0, 1, 2...). - Minor revisions always start at 0 regardless of this setting (e.g., 1-0, 1-1, 1-2, 2-0...). - This only affects how revisions are displayed, not how they are stored in the database. - - - - - )} + + + + Revision Format + + {({ closeDropdown }) => ( + <> + { + setRevisionFormat("major-only"); + closeDropdown(); + }} + active={revisionFormat === "major-only"} + > + {useNumberRevisions + ? revisionStartAtOne + ? "Major Only (1, 2, 3...)" + : "Major Only (0, 1, 2...)" + : "Major Only (A, B, C...)"} + + { + setRevisionFormat("major-minor"); + closeDropdown(); + }} + active={revisionFormat === "major-minor"} + > + {useNumberRevisions + ? revisionStartAtOne + ? "Major-Minor (1-0, 1-1, 2-0...)" + : "Major-Minor (0-0, 0-1, 1-0...)" + : "Major-Minor (A-A, A-B, B-A...)"} + + + )} + + + Choose the format for {useNumberRevisions ? "number" : "letter"} + -based revisions. Major-minor format allows for more granular + versioning with sub-revisions. + {useNumberRevisions && + `For number-based revisions, the starting value shown above depends on the "Start major revisions at 1" setting.`} + + + + - - - - Revision Format - + + + + Part Number Template + - Part type (PRT, ASM, PCBA, DOC)\n" + + "• - Numeric part number\n" + + "• - Major revision (A, B, C or 0, 1, 2)\n" + + "• - Minor revision (A, B, C or 0, 1, 2)\n" + + "• - Complete revision string (includes separator)\n" + + "• - Project number from associated project\n" + + "• - Day from creation date (01-31)\n" + + "• - Month from creation date (01-12)\n" + + "• - Year from creation date (e.g., 2025)\n\n" + + "Example: '-' → 'PRT10001-A-0'" } - variant="outline-secondary" - > - {({ closeDropdown }) => ( - <> - { - setRevisionFormat("major-only"); - closeDropdown(); - }} - active={revisionFormat === "major-only"} - > - {useNumberRevisions - ? (revisionStartAtOne ? "Major Only (1, 2, 3...)" : "Major Only (0, 1, 2...)") - : "Major Only (A, B, C...)"} - - { - setRevisionFormat("major-minor"); - closeDropdown(); - }} - active={revisionFormat === "major-minor"} - > - {useNumberRevisions - ? (revisionStartAtOne ? "Major-Minor (1-0, 1-1, 2-0...)" : "Major-Minor (0-0, 0-1, 1-0...)") - : "Major-Minor (A-A, A-B, B-A...)"} - - - )} - - - Choose the format for {useNumberRevisions ? "number" : "letter"}-based revisions. Major-minor format allows for more granular versioning with sub-revisions. - {useNumberRevisions && `For number-based revisions, the starting value shown above depends on the "Start major revisions at 1" setting.`} - - - - - - - - - - Part Number Template - - Part type (PRT, ASM, PCBA, DOC)\n" + - "• - Numeric part number\n" + - "• - Major revision (A, B, C or 0, 1, 2)\n" + - "• - Minor revision (A, B, C or 0, 1, 2)\n" + - "• - Complete revision string (includes separator)\n" + - "• - Project number from associated project\n" + - "• - Day from creation date (01-31)\n" + - "• - Month from creation date (01-12)\n" + - "• - Year from creation date (e.g., 2025)\n\n" + - "Example: '-' → 'PRT10001-A-0'" - } - /> - - setFullPartNumberTemplate(e.target.value)} - placeholder="" - style={{ fontFamily: 'monospace' }} /> + + setFullPartNumberTemplate(e.target.value)} + placeholder="" + style={{ fontFamily: "monospace" }} + /> + + Preview: {renderTemplateWithHighlights(fullPartNumberTemplate)} + + {isLoadingPreview ? ( - Preview: {renderTemplateWithHighlights(fullPartNumberTemplate)} + Loading examples... - {isLoadingPreview ? ( - - Loading examples... + ) : previewExamples.length > 0 ? ( +
+ + Examples: - ) : previewExamples.length > 0 ? ( -
- - Examples: + {previewExamples.map((example, index) => ( + + • {example.description}:{" "} + + {example.formatted} + - {previewExamples.map((example, index) => ( - - • {example.description}: {example.formatted} - - ))} -
- ) : null} - - - + ))} +
+ ) : null} +
+ +
- - - - - Standalone Revision Template - - Major revision (A, B, C or 0, 1, 2)\n" + - "• - Minor revision (A, B, C or 0, 1, 2)\n\n" + - "Common examples:\n" + - "• '' → 'A' or '0'\n" + - "• '-' → 'A-0' or '0-1'\n" + - "• 'Rev ' → 'Rev A' or 'Rev 0'\n" + - "• 'v.' → 'vA.0' or 'v0.1'" - } - /> - - setFormattedRevisionTemplate(e.target.value)} - placeholder="" - style={{ fontFamily: 'monospace' }} + + + + + Standalone Revision Template + - Major revision (A, B, C or 0, 1, 2)\n" + + "• - Minor revision (A, B, C or 0, 1, 2)\n\n" + + "Common examples:\n" + + "• '' → 'A' or '0'\n" + + "• '-' → 'A-0' or '0-1'\n" + + "• 'Rev ' → 'Rev A' or 'Rev 0'\n" + + "• 'v.' → 'vA.0' or 'v0.1'" + } /> + + setFormattedRevisionTemplate(e.target.value)} + placeholder="" + style={{ fontFamily: "monospace" }} + /> + + This controls how revisions are displayed in standalone contexts + (e.g., revision columns in tables). + + + Preview:{" "} + {renderTemplateWithHighlights(formattedRevisionTemplate)} + + {isLoadingRevisionPreview ? ( - This controls how revisions are displayed in standalone contexts (e.g., revision columns in tables). - - - Preview: {renderTemplateWithHighlights(formattedRevisionTemplate)} + Loading examples... - {isLoadingRevisionPreview ? ( - - Loading examples... + ) : revisionPreviewExamples.length > 0 ? ( +
+ + Examples: - ) : revisionPreviewExamples.length > 0 ? ( -
- - Examples: + {revisionPreviewExamples.map((example, index) => ( + + • {example.description}:{" "} + + {example.formatted} + - {revisionPreviewExamples.map((example, index) => ( - - • {example.description}: {example.formatted} - - ))} -
- ) : null} - - - + ))} +
+ ) : null} +
+ +
- {/* Available Keywords Reference - applies to both templates above */} - - -
-
- - Available Template Keywords - -
- {availableKeywords.map((kw, index) => ( -
- - {kw.keyword} - - {kw.description} -
- ))} -
-
-
- -
+ {/* Available Keywords Reference - applies to both templates above */} + + +
+
+ + Available Template Keywords + +
+ {availableKeywords.map((kw, index) => ( +
+ + {kw.keyword} + + {kw.description} +
+ ))} +
+
+
+ +
- - -
- Current Configuration: -
    + + +
    + Current Configuration: +
      +
    • + Revision Type:{" "} + {useNumberRevisions ? "Number-based" : "Letter-based"} +
    • +
    • + Format:{" "} + {revisionFormat === "major-only" + ? "Major only" + : "Major-minor"} +
    • + {useNumberRevisions && (
    • - Revision Type: {useNumberRevisions ? "Number-based" : "Letter-based"} + Major revision starts at:{" "} + {revisionStartAtOne ? "1" : "0"}
    • -
    • - Format: {revisionFormat === "major-only" ? "Major only" : "Major-minor"} -
    • - {useNumberRevisions && ( -
    • - Major revision starts at: {revisionStartAtOne ? "1" : "0"} -
    • - )} -
    • - Part Number Template: {renderTemplateWithHighlights(fullPartNumberTemplate)} -
    • -
    • - Standalone Revision Template: {renderTemplateWithHighlights(formattedRevisionTemplate)} -
    • -
    -
    - -
    + )} +
  • + Part Number Template:{" "} + {renderTemplateWithHighlights(fullPartNumberTemplate)} +
  • +
  • + Standalone Revision Template:{" "} + {renderTemplateWithHighlights(formattedRevisionTemplate)} +
  • +
+
+ +
- - -
- - {isUpdating ? "Saving..." : "Save Settings"} - -
- -
- + + +
+ + {isUpdating ? "Saving..." : "Save Settings"} + +
+ +
+ ); }; diff --git a/dokuly/organizations/revision_utils.py b/dokuly/organizations/revision_utils.py index 9b4309a..7a59f10 100644 --- a/dokuly/organizations/revision_utils.py +++ b/dokuly/organizations/revision_utils.py @@ -130,11 +130,13 @@ def build_full_part_number( template = org.full_part_number_template use_number_revisions = org.use_number_revisions start_at_one = org.start_major_revision_at_one + revision_format = org.revision_format except Organization.DoesNotExist: # Fallback to defaults template = "" use_number_revisions = False start_at_one = False + revision_format = "major-only" return build_full_part_number_from_template( template=template, @@ -146,6 +148,7 @@ def build_full_part_number( start_at_one=start_at_one, project_number=project_number, created_at=created_at, + revision_format=revision_format, ) @@ -157,6 +160,7 @@ def build_formatted_revision( revision_count_minor: int, project_number: Optional[str] = None, created_at: Optional[object] = None, + revision_format: Optional[str] = None, ) -> str: """ Build a full part number using organization settings and template. @@ -192,11 +196,14 @@ def build_formatted_revision( template = org.formatted_revision_template use_number_revisions = org.use_number_revisions start_at_one = org.start_major_revision_at_one + # Caller may override revision_format (e.g. documents pass document_revision_format) + effective_revision_format = revision_format if revision_format is not None else org.revision_format except Organization.DoesNotExist: # Fallback to defaults template = "" use_number_revisions = False start_at_one = False + effective_revision_format = revision_format if revision_format is not None else "major-only" return build_full_part_number_from_template( template=template, @@ -208,6 +215,7 @@ def build_formatted_revision( start_at_one=start_at_one, project_number=project_number, created_at=created_at, + revision_format=effective_revision_format, ) @@ -221,6 +229,7 @@ def build_full_part_number_from_template( start_at_one: bool = False, project_number: Optional[str] = None, created_at: Optional[object] = None, + revision_format: str = "major-only", ) -> str: """ Build a full part number from a template and revision counts. @@ -275,11 +284,17 @@ def build_full_part_number_from_template( # If created_at is not a datetime object or is invalid, use empty strings pass + # Build the combined value based on revision_format + if revision_format == "major-minor": + revision_combined = f"{major_formatted}-{minor_formatted}" + else: + revision_combined = major_formatted + # Replace template variables result = template result = result.replace("", prefix_str) result = result.replace("", part_number_str) - result = result.replace("", major_formatted) + result = result.replace("", revision_combined) result = result.replace("", major_formatted) result = result.replace("", minor_formatted) result = result.replace("", project_number_str) @@ -660,11 +675,13 @@ def build_full_document_number( # Use document-specific revision settings use_number_revisions = org.document_use_number_revisions start_at_one = org.document_start_major_revision_at_one + revision_format = org.document_revision_format except Organization.DoesNotExist: # Fallback to defaults template = "-" use_number_revisions = False start_at_one = False + revision_format = "major-only" return build_full_document_number_from_template( template=template, @@ -677,6 +694,7 @@ def build_full_document_number( project_number=project_number, part_number=part_number, created_at=created_at, + revision_format=revision_format, ) @@ -691,6 +709,7 @@ def build_full_document_number_from_template( project_number: Optional[str] = None, part_number: Optional[str] = None, created_at: Optional[object] = None, + revision_format: str = "major-only", ) -> str: """ Build a full document number from a template and revision counts. @@ -748,13 +767,19 @@ def build_full_document_number_from_template( # If created_at is not a datetime object or is invalid, use empty strings pass + # Build the combined value based on revision_format + if revision_format == "major-minor": + revision_combined = f"{major_formatted}-{minor_formatted}" + else: + revision_combined = major_formatted + # Replace template variables result = template result = result.replace("", prefix_str) result = result.replace("", document_number_str) result = result.replace("", project_number_str) result = result.replace("", part_number_str) - result = result.replace("", major_formatted) + result = result.replace("", revision_combined) result = result.replace("", major_formatted) result = result.replace("", minor_formatted) result = result.replace("", day_str) diff --git a/dokuly/organizations/views.py b/dokuly/organizations/views.py index f6e6320..18a1746 100644 --- a/dokuly/organizations/views.py +++ b/dokuly/organizations/views.py @@ -601,6 +601,7 @@ def preview_part_number_template(request): template = request.data.get('template', '') use_number_revisions = request.data.get('use_number_revisions', False) start_at_one = request.data.get('start_major_revision_at_one', False) + revision_format = request.data.get('revision_format', 'major-only') # Create sample datetime for date-based variables sample_date = datetime(2025, 1, 15, 10, 30, 0) # Jan 15, 2025 @@ -621,6 +622,7 @@ def preview_part_number_template(request): start_at_one=start_at_one, project_number='PRJ001', created_at=sample_date, + revision_format=revision_format, ) }) @@ -637,6 +639,7 @@ def preview_part_number_template(request): start_at_one=start_at_one, project_number='PRJ042', created_at=sample_date, + revision_format=revision_format, ) }) @@ -653,6 +656,7 @@ def preview_part_number_template(request): start_at_one=start_at_one, project_number='PRJ100', created_at=sample_date, + revision_format=revision_format, ) }) @@ -708,6 +712,7 @@ def preview_formatted_revision_template(request): revision_count_minor=0, use_number_revisions=use_number_revisions, start_at_one=start_at_one, + revision_format=revision_format, ) }) @@ -723,6 +728,7 @@ def preview_formatted_revision_template(request): revision_count_minor=1, use_number_revisions=use_number_revisions, start_at_one=start_at_one, + revision_format=revision_format, ) }) @@ -737,6 +743,7 @@ def preview_formatted_revision_template(request): revision_count_minor=0, use_number_revisions=use_number_revisions, start_at_one=start_at_one, + revision_format=revision_format, ) }) @@ -777,6 +784,7 @@ def preview_document_number_template(request): template = request.data.get('template', '-') use_number_revisions = request.data.get('use_number_revisions', False) start_at_one = request.data.get('start_major_revision_at_one', False) + revision_format = request.data.get('revision_format', 'major-only') # Create sample datetime for date-based variables sample_date = datetime(2025, 1, 15, 10, 30, 0) # Jan 15, 2025 @@ -798,6 +806,7 @@ def preview_document_number_template(request): project_number='1001', part_number='10001', created_at=sample_date, + revision_format=revision_format, ) }) @@ -815,6 +824,7 @@ def preview_document_number_template(request): project_number='2042', part_number='20045', created_at=sample_date, + revision_format=revision_format, ) }) @@ -832,6 +842,7 @@ def preview_document_number_template(request): project_number='3100', part_number='30012', created_at=sample_date, + revision_format=revision_format, ) })