Преглед изворни кода

Add purple envelope delivery paperwork generation

master
Daniel Covington пре 1 дан
родитељ
комит
f5795db6ed
11 измењених фајлова са 1413 додато и 4 уклоњено
  1. +217
    -1
      App/Controllers/Kit/KitController.asp
  2. +31
    -0
      App/DomainModels/KitRepository.asp
  3. +10
    -0
      App/ViewModels/KitViewModels.asp
  4. +5
    -0
      App/Views/Kit/SwitchBoardPurpleEnvelopeEdit.asp
  5. +2
    -2
      App/app.config.asp
  6. +275
    -0
      Data/Delivery_Labels.rep
  7. +331
    -0
      Data/Delivery_PackingSlip.rep
  8. +24
    -0
      Data/Migrations/Migration_21_Create_DeliveryLabelPage_Table.asp
  9. +1
    -0
      Data/Migrations/migrate.asp
  10. +116
    -1
      Tests/TestCase_PurpleEnvelopeReport.asp
  11. +401
    -0
      _bmad-output/implementation-artifacts/tech-spec-print-delivery-paperwork-purple-envelope.md

+ 217
- 1
App/Controllers/Kit/KitController.asp Прегледај датотеку

@@ -98,7 +98,8 @@ Class KitController
End Sub

Public Sub SwitchBoardPurpleEnvelopeEdit

Flash.ShowErrorsIfPresent
Flash.ShowSuccessIfPresent
dim id : id = Request.QueryString("Id")
set Model = new SwitchBoard_ViewModel_Class
set Model.Kit = KitRepository.SwitchBoardPurpleEnvelopeEditFindById(id)
@@ -119,6 +120,221 @@ Class KitController
%> <!--#include file="../../Views/Kit/SwitchBoardPurpleEnvelopeEdit.asp"--> <%
End Sub

Public Sub PrintDeliveryPaperwork
dim id : id = Trim(Request.QueryString("Id") & "")
If Len(id) = 0 Or Not IsNumeric(id) Then
Flash.AddError "Unable to print delivery paperwork because the kit ID is missing or invalid."
MVC.RedirectToAction "SwitchBoardPurpleEnvelopsIndex"
Exit Sub
End If

dim kitId : kitId = CLng(id)
dim kitInfo
On Error Resume Next
set kitInfo = KitRepository.SwitchBoardPurpleEnvelopeEditFindById(kitId)
If Err.Number <> 0 Then
dim loadErrDescription : loadErrDescription = Err.Description
Err.Clear
On Error GoTo 0
Flash.AddError "Unable to load the requested kit. " & loadErrDescription
MVC.RedirectToAction "SwitchBoardPurpleEnvelopsIndex"
Exit Sub
End If
On Error GoTo 0

If UCase(Trim(kitInfo.Status & "")) <> "DONE" Then
Flash.AddError "Delivery paperwork can only be printed when the kit status is Done."
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If

dim inkjetCount : inkjetCount = 0
If IsNumeric(kitInfo.LabelCount) Then
inkjetCount = CLng(kitInfo.LabelCount)
End If
If inkjetCount <= 0 Then
Flash.AddError "Delivery paperwork cannot be generated because no labels were found for this kit."
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If

dim appPath : appPath = Request.ServerVariables("APPL_PHYSICAL_PATH")
dim labelsTemplatePath : labelsTemplatePath = appPath & "Data\Delivery_Labels.rep"
dim packingSlipTemplatePath : packingSlipTemplatePath = appPath & "Data\Delivery_PackingSlip.rep"
If FSO.FileExists(labelsTemplatePath) = False Then
Flash.AddError "Delivery labels template was not found: Data\Delivery_Labels.rep"
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If
If FSO.FileExists(packingSlipTemplatePath) = False Then
Flash.AddError "Delivery packing slip template was not found: Data\Delivery_PackingSlip.rep"
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If

dim totalBoxes : totalBoxes = Int((inkjetCount + 1099) / 1100)
If totalBoxes <= 0 Then
Flash.AddError "Delivery paperwork cannot be generated because no shipping boxes were calculated."
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If

dim jurisdiction : jurisdiction = Trim(kitInfo.Jurisdiction & "")
dim jCode : jCode = Trim(kitInfo.JCode & "")
dim jobNumber : jobNumber = Trim(kitInfo.JobNumber & "")

dim pages : set pages = new LinkedList_Class
dim boxNum : boxNum = totalBoxes
dim pageNum : pageNum = 1
dim page, slot, labelText

Do While boxNum >= 1
set page = new DeliveryLabelPage_Class
page.PageNum = pageNum
For slot = 1 To 6
labelText = ""
If boxNum >= 1 Then
labelText = jurisdiction & vbCrLf & _
"Box " & boxNum & " of " & totalBoxes & vbCrLf & _
"Total Printed " & inkjetCount & vbCrLf & _
"Job# " & jobNumber
boxNum = boxNum - 1
End If

Select Case slot
Case 1 : page.Label1 = labelText
Case 2 : page.Label2 = labelText
Case 3 : page.Label3 = labelText
Case 4 : page.Label4 = labelText
Case 5 : page.Label5 = labelText
Case 6 : page.Label6 = labelText
End Select
Next

pages.Push page
pageNum = pageNum + 1
Loop

dim exportFolder : exportFolder = ExportDirectory & jCode & "-" & jurisdiction
On Error Resume Next
If FSO.FolderExists(exportFolder) = False Then
FSO.CreateFolder(exportFolder)
End If
If Err.Number <> 0 Then
dim folderErrDescription : folderErrDescription = Err.Description
Err.Clear
On Error GoTo 0
Flash.AddError "Unable to create the delivery export folder. " & folderErrDescription
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If

dim labelsFilename : labelsFilename = jCode & "-" & jurisdiction & "_delivery_labels.pdf"
dim packingSlipFilename : packingSlipFilename = jCode & "-" & jurisdiction & "_delivery_packing_slip.pdf"
dim labelsFinalPath : labelsFinalPath = exportFolder & "\" & labelsFilename
dim packingSlipFinalPath : packingSlipFinalPath = exportFolder & "\" & packingSlipFilename
dim labelsTempPath : labelsTempPath = appPath & "Data\" & jCode & "-" & jurisdiction & "_delivery_labels.tmp.pdf"
dim packingSlipTempPath : packingSlipTempPath = appPath & "Data\" & jCode & "-" & jurisdiction & "_delivery_packing_slip.tmp.pdf"

If FSO.FileExists(labelsTempPath) Then FSO.DeleteFile labelsTempPath
If FSO.FileExists(packingSlipTempPath) Then FSO.DeleteFile packingSlipTempPath
If Err.Number <> 0 Then
dim tempErrDescription : tempErrDescription = Err.Description
Err.Clear
On Error GoTo 0
Flash.AddError "Unable to clear previous temporary delivery paperwork files. " & tempErrDescription
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If
On Error GoTo 0

dim databaseConnectionString
If dev = true Then
databaseConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Engine Type=5;Data Source=" & appPath & "Data\webdata - Copy.mdb;"
Else
databaseConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Engine Type=5;Data Source=C:\inetpub\Data\webdata - Copy.mdb;"
End If

On Error Resume Next
KitRepository.SaveDeliveryLabelPages kitId, pages
If Err.Number <> 0 Then
dim stageErrDescription : stageErrDescription = Err.Description
Err.Clear
On Error GoTo 0
Flash.AddError "Unable to stage delivery label data. " & stageErrDescription
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If

dim labelsReport : set labelsReport = Server.CreateObject("ReportMan.ReportManX")
labelsReport.Filename = labelsTemplatePath
labelsReport.SetDatabaseConnectionString "TRACKINGKITLABELS", databaseConnectionString
labelsReport.Preview = False
labelsReport.ShowProgress = False
labelsReport.ShowPrintDialog = False
labelsReport.SetParamValue "PBKITID", CInt(kitId)
labelsReport.SaveToPdf labelsTempPath, 1
set labelsReport = Nothing

If Err.Number <> 0 Then
dim labelsErrDescription : labelsErrDescription = Err.Description
Err.Clear
On Error GoTo 0
Flash.AddError "Unable to generate the delivery labels PDF. " & labelsErrDescription
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If

dim slipReport : set slipReport = Server.CreateObject("ReportMan.ReportManX")
slipReport.Filename = packingSlipTemplatePath
slipReport.SetDatabaseConnectionString "TRACKINGKITLABELS", databaseConnectionString
slipReport.Preview = False
slipReport.ShowProgress = False
slipReport.ShowPrintDialog = False
slipReport.SetParamValue "PBKITID", CInt(kitId)
slipReport.SaveToPdf packingSlipTempPath, 1
set slipReport = Nothing

If Err.Number <> 0 Then
dim slipErrDescription : slipErrDescription = Err.Description
Err.Clear
On Error GoTo 0
Flash.AddError "Unable to generate the delivery packing slip PDF. " & slipErrDescription
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If

If FSO.FileExists(labelsFinalPath) Then FSO.DeleteFile labelsFinalPath
If FSO.FileExists(packingSlipFinalPath) Then FSO.DeleteFile packingSlipFinalPath
FSO.MoveFile labelsTempPath, labelsFinalPath
FSO.MoveFile packingSlipTempPath, packingSlipFinalPath

If Err.Number <> 0 Then
dim moveErrDescription : moveErrDescription = Err.Description
Err.Clear
On Error GoTo 0
Flash.AddError "Delivery paperwork PDFs were generated but could not be moved into the export folder. " & moveErrDescription
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If

On Error GoTo 0
On Error Resume Next
KitRepository.DeleteDeliveryLabelPages kitId
If Err.Number <> 0 Then
dim cleanupErrDescription : cleanupErrDescription = Err.Description
Err.Clear
On Error GoTo 0
Flash.AddError "Delivery paperwork PDFs were generated, but staging cleanup failed. " & cleanupErrDescription
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
Exit Sub
End If
On Error GoTo 0

Flash.Success = "Delivery paperwork generated successfully."
MVC.RedirectToActionExt "SwitchBoardPurpleEnvelopeEdit", Array("Id", kitId)
End Sub

Public Sub Index

dim page_size : page_size = 10


+ 31
- 0
App/DomainModels/KitRepository.asp Прегледај датотеку

@@ -354,6 +354,37 @@ Public Sub Update(model)
model.ID)
End Sub

Public Sub SaveDeliveryLabelPages(ByVal kitId, ByVal pages)
dim sql, pageIt, page
sql = "INSERT INTO [DeliveryLabelPage] ([KitID],[PageNum],[Label1],[Label2],[Label3],[Label4],[Label5],[Label6]) VALUES (?,?,?,?,?,?,?,?)"

DAL.BeginTransaction
On Error Resume Next

DAL.Execute "DELETE FROM [DeliveryLabelPage] WHERE [KitID] = ?", CLng(kitId)

set pageIt = pages.Iterator
Do While Err.Number = 0 And pageIt.HasNext
set page = pageIt.GetNext()
DAL.Execute sql, Array(CLng(kitId), CInt(page.PageNum), page.Label1, page.Label2, page.Label3, page.Label4, page.Label5, page.Label6)
Loop

If Err.Number <> 0 Then
dim errNumber : errNumber = Err.Number
dim errDescription : errDescription = Err.Description
DAL.RollbackTransaction
On Error GoTo 0
Err.Raise errNumber, "KitRepository_Class.SaveDeliveryLabelPages", errDescription
End If

On Error GoTo 0
DAL.CommitTransaction
End Sub

Public Sub DeleteDeliveryLabelPages(ByVal kitId)
DAL.Execute "DELETE FROM [DeliveryLabelPage] WHERE [KitID] = ?", CLng(kitId)
End Sub

Public Sub Delete(id)
dim sql : sql = "DELETE FROM [Kit] WHERE [ID] = ?"
DAL.Execute sql, id


+ 10
- 0
App/ViewModels/KitViewModels.asp Прегледај датотеку

@@ -49,6 +49,16 @@ Class SwitchBoard_PurpleEnvelopesViewModel_Class
Public RecordCount
End Class

Class DeliveryLabelPage_Class
Public PageNum
Public Label1
Public Label2
Public Label3
Public Label4
Public Label5
Public Label6
End Class

Class Create_ViewModel_Class
Public Title
Public JobNumber


+ 5
- 0
App/Views/Kit/SwitchBoardPurpleEnvelopeEdit.asp Прегледај датотеку

@@ -95,6 +95,11 @@
<p><strong>Created On:</strong> <%= Model.Kit.CreatedOn %></p>
<p><strong>Labels Printed On :</strong> <%= Model.Kit.LabelsPrinted %></p>
<p><strong>Exported to SnailWorks On:</strong> <%= Model.Kit.ExportedToSnailWorks %></p>
<% If Model.Kit.Status = "Done" Then %>
<p>
<%= HTML.LinkToExt("<i class='glyphicon glyphicon-print'></i> Print Delivery Paperwork", "Kit", "PrintDeliveryPaperwork", Array("Id", Model.Kit.ID), Array("class", "btn btn-primary")) %>
</p>
<% End If %>
<% IF Model.Kit.Status = "Ready To Assign STIDS" THEN %>
<%= HTML.FormTag("Kit","SwitchBoardPurpleEnvelopeEditPost",empty,empty) %>
<%


+ 2
- 2
App/app.config.asp Прегледај датотеку

@@ -11,9 +11,9 @@ dev = true
dim ExportDirectory
select case dev
case "local"
ExportDirectory = "D:\Development\Tracking_Kits\uploads"
ExportDirectory = "D:\Development\Tracking_Kits\uploads\"
case true
ExportDirectory = "D:\Development\Tracking_Kits\uploads"
ExportDirectory = "D:\Development\Tracking_Kits\uploads\"
case else
ExportDirectory ="\\kci-syn-cl01\PC Transfer\TrackingDataExport\"



+ 275
- 0
Data/Delivery_Labels.rep Прегледај датотеку

@@ -0,0 +1,275 @@
object TRpReport
Pagesize = rpPageSizeCustom
PageHeight = 7920
PageWidth = 12240
PageBackColor = 16777215
LeftMargin = 180
TopMargin = 180
RightMargin = 180
BottomMargin = 180
SubReports = <
item
SubReport = TRpSubReport0
end>
DataInfo = <
item
Alias = 'DELIVERYLABELS'
DatabaseAlias = 'TRACKINGKITLABELS'
SQL =
'SELECT Label1, Label2, Label3, Label4, Label5, Label6 FROM Deliv' +
'eryLabelPage WHERE KitID = PBKITID ORDER BY PageNum'
end>
DatabaseInfo = <
item
Alias = 'TRACKINGKITLABELS'
LoadParams = True
LoadDriverParams = True
LoginPrompt = False
Driver = rpdataado
ReportTable = 'REPMAN_REPORTS'
ReportSearchField = 'REPORT_NAME'
ReportField = 'REPORT'
ReportGroupsTable = 'REPMAN_GROUPS'
ADOConnectionString =
'Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Engine Type=5;Data So' +
'urce=C:\inetpub\Data\webdata - Copy.mdb;Persist Security Info=Fa' +
'lse;'
end>
Params = <
item
Name = 'PBKITID'
AllowNulls = False
Value = '1'
ParamType = rpParamInteger
Datasets.Strings = (
'DELIVERYLABELS')
SearchDataset = 'DELIVERYLABELS'
SearchParam = 'PBKITID'
Description = ''
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end>
StreamFormat = rpStreamText
ReportAction = []
Type1Font = poHelvetica
WFontName = 'Arial'
LFontName = 'Helvetica'
object TRpSubReport0: TRpSubReport
Sections = <
item
Section = TRpSection0
end>
Alias = 'DELIVERYLABELS'
end
object TRpSection0: TRpSection
Width = 12240
Height = 7920
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpLabel0
end
item
Component = TRpExpression1
end
item
Component = TRpExpression2
end
item
Component = TRpExpression3
end
item
Component = TRpExpression4
end
item
Component = TRpExpression5
end
item
Component = TRpExpression6
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
BackStyle = baPrint
DrawStyle = rpDrawStretch
CachedImage = rpCachedFixed
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpLabel0: TRpLabel
Width = 3600
Height = 240
PosX = 300
PosY = 180
Type1Font = poHelvetica
FontSize = 9
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Delivery Labels'
end
object TRpExpression1: TRpExpression
Width = 5400
Height = 1800
PosX = 360
PosY = 720
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = True
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'DELIVERYLABELS.Label1'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression2: TRpExpression
Width = 5400
Height = 1800
PosX = 6480
PosY = 720
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = True
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'DELIVERYLABELS.Label2'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression3: TRpExpression
Width = 5400
Height = 1800
PosX = 360
PosY = 2880
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = True
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'DELIVERYLABELS.Label3'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression4: TRpExpression
Width = 5400
Height = 1800
PosX = 6480
PosY = 2880
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = True
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'DELIVERYLABELS.Label4'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression5: TRpExpression
Width = 5400
Height = 1800
PosX = 360
PosY = 5040
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = True
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'DELIVERYLABELS.Label5'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression6: TRpExpression
Width = 5400
Height = 1800
PosX = 6480
PosY = 5040
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = True
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'DELIVERYLABELS.Label6'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
end

+ 331
- 0
Data/Delivery_PackingSlip.rep Прегледај датотеку

@@ -0,0 +1,331 @@
object TRpReport
Pagesize = rpPageSizeCustom
PageHeight = 7920
PageWidth = 12240
PageBackColor = 16777215
LeftMargin = 360
TopMargin = 360
RightMargin = 360
BottomMargin = 360
SubReports = <
item
SubReport = TRpSubReport0
end>
DataInfo = <
item
Alias = 'PACKINGSLIP'
DatabaseAlias = 'TRACKINGKITLABELS'
SQL =
'SELECT Kit.JobNumber AS JobNumber, Jurisdiction.Name AS Jurisdic' +
'tion, (SELECT COUNT(*) FROM InkjetRecords WHERE KitID = Kit.ID) A' +
'S TotalPrinted, Int(((SELECT COUNT(*) FROM InkjetRecords WHERE Kit' +
'ID = Kit.ID) + 1099) / 1100) AS TotalBoxes FROM Kit INNER JOIN Ju' +
'risdiction ON Kit.JCode = Jurisdiction.JCode WHERE Kit.ID = PBKITI' +
'D'
end>
DatabaseInfo = <
item
Alias = 'TRACKINGKITLABELS'
LoadParams = True
LoadDriverParams = True
LoginPrompt = False
Driver = rpdataado
ReportTable = 'REPMAN_REPORTS'
ReportSearchField = 'REPORT_NAME'
ReportField = 'REPORT'
ReportGroupsTable = 'REPMAN_GROUPS'
ADOConnectionString =
'Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Engine Type=5;Data So' +
'urce=C:\inetpub\Data\webdata - Copy.mdb;Persist Security Info=Fa' +
'lse;'
end>
Params = <
item
Name = 'PBKITID'
AllowNulls = False
Value = '1'
ParamType = rpParamInteger
Datasets.Strings = (
'PACKINGSLIP')
SearchDataset = 'PACKINGSLIP'
SearchParam = 'PBKITID'
Description = ''
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end>
StreamFormat = rpStreamText
ReportAction = []
Type1Font = poHelvetica
WFontName = 'Arial'
LFontName = 'Helvetica'
object TRpSubReport0: TRpSubReport
Sections = <
item
Section = TRpSection0
end>
Alias = 'PACKINGSLIP'
end
object TRpSection0: TRpSection
Width = 12240
Height = 7200
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpLabel0
end
item
Component = TRpLabel1
end
item
Component = TRpExpression1
end
item
Component = TRpLabel2
end
item
Component = TRpExpression2
end
item
Component = TRpLabel3
end
item
Component = TRpExpression3
end
item
Component = TRpLabel4
end
item
Component = TRpExpression4
end
item
Component = TRpLabel5
end
item
Component = TRpLabel6
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
BackStyle = baPrint
DrawStyle = rpDrawStretch
CachedImage = rpCachedFixed
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpLabel0: TRpLabel
Width = 3600
Height = 360
PosX = 360
PosY = 360
Type1Font = poHelvetica
FontSize = 14
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Delivery Packing Slip'
end
object TRpLabel1: TRpLabel
Width = 2280
Height = 240
PosX = 360
PosY = 1260
Type1Font = poHelvetica
FontSize = 11
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Jurisdiction:'
end
object TRpExpression1: TRpExpression
Width = 5400
Height = 240
PosX = 3000
PosY = 1260
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'PACKINGSLIP.Jurisdiction'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel2: TRpLabel
Width = 2280
Height = 240
PosX = 360
PosY = 1800
Type1Font = poHelvetica
FontSize = 11
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Job Number:'
end
object TRpExpression2: TRpExpression
Width = 5400
Height = 240
PosX = 3000
PosY = 1800
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'PACKINGSLIP.JobNumber'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel3: TRpLabel
Width = 2280
Height = 240
PosX = 360
PosY = 2340
Type1Font = poHelvetica
FontSize = 11
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Total Printed:'
end
object TRpExpression3: TRpExpression
Width = 5400
Height = 240
PosX = 3000
PosY = 2340
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'PACKINGSLIP.TotalPrinted'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel4: TRpLabel
Width = 2280
Height = 240
PosX = 360
PosY = 2880
Type1Font = poHelvetica
FontSize = 11
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Total Boxes:'
end
object TRpExpression4: TRpExpression
Width = 5400
Height = 240
PosX = 3000
PosY = 2880
Type1Font = poHelvetica
FontSize = 11
Alignment = 0
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'PACKINGSLIP.TotalBoxes'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel5: TRpLabel
Width = 2880
Height = 240
PosX = 360
PosY = 4320
Type1Font = poHelvetica
FontSize = 11
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Received By: ____________________'
end
object TRpLabel6: TRpLabel
Width = 2880
Height = 240
PosX = 360
PosY = 5040
Type1Font = poHelvetica
FontSize = 11
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Date: __________________________'
end
end

+ 24
- 0
Data/Migrations/Migration_21_Create_DeliveryLabelPage_Table.asp Прегледај датотеку

@@ -0,0 +1,24 @@
<%
Class Migration_21_Create_DeliveryLabelPage_Table
Public Migration

Public Sub Up
Migration.Do "CREATE TABLE [DeliveryLabelPage] (" & _
"[ID] COUNTER CONSTRAINT [PrimaryKey] PRIMARY KEY, " & _
"[KitID] LONG NOT NULL, " & _
"[PageNum] INTEGER NOT NULL, " & _
"[Label1] MEMO, " & _
"[Label2] MEMO, " & _
"[Label3] MEMO, " & _
"[Label4] MEMO, " & _
"[Label5] MEMO, " & _
"[Label6] MEMO);"
End Sub

Public Sub Down
Migration.Do "DROP TABLE [DeliveryLabelPage];"
End Sub
End Class

Migrations.Add "Migration_21_Create_DeliveryLabelPage_Table"
%>

+ 1
- 0
Data/Migrations/migrate.asp Прегледај датотеку

@@ -48,6 +48,7 @@ Migrations.Tracing = false
<!--#include file="Migration_18_Create_CustomOfficeCopyJob_Table.asp"-->
<!--#include file="Migration_19_Create_Colors_Table.asp"-->
<!--#include file="Migration_20_Add_ColorId_To_InkjetRecords.asp"-->
<!--#include file="Migration_21_Create_DeliveryLabelPage_Table.asp"-->
<%
Sub HandleMigration
putl "<b>Starting Version: " & Migrations.Version & "</b>"


+ 116
- 1
Tests/TestCase_PurpleEnvelopeReport.asp Прегледај датотеку

@@ -11,6 +11,7 @@ Class PurpleEnvelopeReport_Tests
Public Sub Setup
m_tempDbPath = CreateDisposableDatabaseCopy()
UseDisposableDatabase m_tempDbPath
EnsureDeliveryLabelPageTable
End Sub

Public Sub Teardown
@@ -27,9 +28,14 @@ Class PurpleEnvelopeReport_Tests
"Test_UpdateColorForKit_Updates_All_Seeded_Rows_For_The_Target_Kit", _
"Test_UpdateColorForPrecinct_Updates_Only_The_Targeted_Precinct", _
"Test_SwitchBoardPurpleEnvelopeEditFindById_Returns_Seeded_Header_Data", _
"Test_SaveDeliveryLabelPages_Persists_Seeded_Page_Data", _
"Test_SaveDeliveryLabelPages_Replaces_Existing_Pages_For_The_Kit", _
"Test_DeleteDeliveryLabelPages_Removes_All_Staged_Pages_For_The_Kit", _
"Test_KitController_Post_Actions_Still_Delegate_To_Color_Update_Repositories", _
"Test_Report_View_Keeps_Print_Only_CSS_Contract", _
"Test_Report_View_Keeps_No_Data_Row_And_Page_Spacer" _
"Test_Report_View_Keeps_No_Data_Row_And_Page_Spacer", _
"Test_Report_View_Only_Shows_Delivery_Paperwork_Link_When_Kit_Is_Done", _
"Test_KitController_Declares_PrintDeliveryPaperwork_Action" _
)
End Function

@@ -139,6 +145,22 @@ Class PurpleEnvelopeReport_Tests
DAL__Singleton.Initialize "Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Engine Type=5;Data Source=" & dbPath & ";"
End Sub

Private Sub EnsureDeliveryLabelPageTable()
On Error Resume Next
DAL.Execute "CREATE TABLE [DeliveryLabelPage] (" & _
"[ID] COUNTER CONSTRAINT [PrimaryKey] PRIMARY KEY, " & _
"[KitID] LONG NOT NULL, " & _
"[PageNum] INTEGER NOT NULL, " & _
"[Label1] MEMO, " & _
"[Label2] MEMO, " & _
"[Label3] MEMO, " & _
"[Label4] MEMO, " & _
"[Label5] MEMO, " & _
"[Label6] MEMO);", empty
Err.Clear
On Error GoTo 0
End Sub

Private Sub ResetDisposableDatabase()
dim tempPath : tempPath = m_tempDbPath
Set DAL__Singleton = Nothing
@@ -204,6 +226,18 @@ Class PurpleEnvelopeReport_Tests
set QueryPrecinctColorMap = map
End Function

Private Function BuildDeliveryLabelPage(ByVal pageNum, ByVal label1, ByVal label2, ByVal label3, ByVal label4, ByVal label5, ByVal label6)
dim page : set page = new DeliveryLabelPage_Class
page.PageNum = pageNum
page.Label1 = label1
page.Label2 = label2
page.Label3 = label3
page.Label4 = label4
page.Label5 = label5
page.Label6 = label6
set BuildDeliveryLabelPage = page
End Function

Public Sub Test_FormatElectionLabel_Returns_Mon_YYYY_For_Valid_Date(T)
T.AssertEqual "May-2026", PurpleEnvelopeReportHelper().FormatElectionLabel("5/26/2026"), "Expected valid dates to render as Mon-YYYY."
End Sub
@@ -358,6 +392,75 @@ Class PurpleEnvelopeReport_Tests
Set model = Nothing
End Sub

Public Sub Test_SaveDeliveryLabelPages_Persists_Seeded_Page_Data(T)
Randomize
dim jCode : jCode = NextJurisdictionCode()
Call SeedJurisdiction(jCode, "City of Lansing")
dim kitId : kitId = SeedPurpleEnvelopeKit(NextSeedKey("JOB"), jCode, "Done")

dim pages : set pages = new LinkedList_Class
pages.Push BuildDeliveryLabelPage(1, "Jurisdiction A" & vbCrLf & "Box 1 of 2", "Jurisdiction A" & vbCrLf & "Box 2 of 2", "", "", "", "")

KitRepository.SaveDeliveryLabelPages kitId, pages

T.AssertEqual 1, QueryScalar("SELECT COUNT(*) FROM [DeliveryLabelPage] WHERE [KitID] = ?", kitId), "Expected one staged page row for the seeded kit."

dim rs : set rs = DAL.Query("SELECT [PageNum], [Label1], [Label2], [Label3], [Label4], [Label5], [Label6] FROM [DeliveryLabelPage] WHERE [KitID] = ? ORDER BY [PageNum]", kitId)
T.Assert Not rs.EOF, "Expected the seeded staged-page row to be present."
T.AssertEqual 1, rs("PageNum"), "Expected staged page numbers to persist."
T.AssertEqual "Jurisdiction A" & vbCrLf & "Box 1 of 2", rs("Label1"), "Expected Label1 to persist exactly."
T.AssertEqual "Jurisdiction A" & vbCrLf & "Box 2 of 2", rs("Label2"), "Expected Label2 to persist exactly."
T.AssertEqual "", rs("Label3"), "Expected unused label slots to persist as empty strings."

Destroy rs
Set pages = Nothing
End Sub

Public Sub Test_SaveDeliveryLabelPages_Replaces_Existing_Pages_For_The_Kit(T)
Randomize
dim jCode : jCode = NextJurisdictionCode()
Call SeedJurisdiction(jCode, "City of Lansing")
dim kitId : kitId = SeedPurpleEnvelopeKit(NextSeedKey("JOB"), jCode, "Done")

dim firstRunPages : set firstRunPages = new LinkedList_Class
firstRunPages.Push BuildDeliveryLabelPage(1, "Run1-Page1-Label1", "", "", "", "", "")
firstRunPages.Push BuildDeliveryLabelPage(2, "Run1-Page2-Label1", "", "", "", "", "")
KitRepository.SaveDeliveryLabelPages kitId, firstRunPages

dim secondRunPages : set secondRunPages = new LinkedList_Class
secondRunPages.Push BuildDeliveryLabelPage(1, "Run2-OnlyPage-Label1", "Run2-OnlyPage-Label2", "", "", "", "")
KitRepository.SaveDeliveryLabelPages kitId, secondRunPages

T.AssertEqual 1, QueryScalar("SELECT COUNT(*) FROM [DeliveryLabelPage] WHERE [KitID] = ?", kitId), "Expected the second save to replace all prior staged rows for the same kit."

dim rs : set rs = DAL.Query("SELECT [PageNum], [Label1], [Label2] FROM [DeliveryLabelPage] WHERE [KitID] = ? ORDER BY [PageNum]", kitId)
T.Assert Not rs.EOF, "Expected a replacement staged row after the second save."
T.AssertEqual 1, rs("PageNum"), "Expected replacement rows to keep their explicit page numbers."
T.AssertEqual "Run2-OnlyPage-Label1", rs("Label1"), "Expected replacement data to overwrite prior Label1 values."
T.AssertEqual "Run2-OnlyPage-Label2", rs("Label2"), "Expected replacement data to overwrite prior Label2 values."

Destroy rs
Set firstRunPages = Nothing
Set secondRunPages = Nothing
End Sub

Public Sub Test_DeleteDeliveryLabelPages_Removes_All_Staged_Pages_For_The_Kit(T)
Randomize
dim jCode : jCode = NextJurisdictionCode()
Call SeedJurisdiction(jCode, "City of Lansing")
dim kitId : kitId = SeedPurpleEnvelopeKit(NextSeedKey("JOB"), jCode, "Done")

dim pages : set pages = new LinkedList_Class
pages.Push BuildDeliveryLabelPage(1, "Delete-Label1", "", "", "", "", "")
pages.Push BuildDeliveryLabelPage(2, "Delete-Label2", "", "", "", "", "")
KitRepository.SaveDeliveryLabelPages kitId, pages

KitRepository.DeleteDeliveryLabelPages kitId
T.AssertEqual 0, QueryScalar("SELECT COUNT(*) FROM [DeliveryLabelPage] WHERE [KitID] = ?", kitId), "Expected DeleteDeliveryLabelPages to remove all staged rows for the kit."

Set pages = Nothing
End Sub

Public Sub Test_KitController_Post_Actions_Still_Delegate_To_Color_Update_Repositories(T)
dim controllerSource : controllerSource = ReadAllText("../App/Controllers/Kit/KitController.asp")

@@ -382,5 +485,17 @@ Class PurpleEnvelopeReport_Tests
T.Assert InStr(viewSource, "class=""print-page-spacer""") > 0, "Expected the repeated-page spacer row to remain in the report header."
T.Assert InStr(viewSource, "No precinct ballot data found for this kit.") > 0, "Expected the empty-state report message to remain unchanged."
End Sub

Public Sub Test_Report_View_Only_Shows_Delivery_Paperwork_Link_When_Kit_Is_Done(T)
dim viewSource : viewSource = ReadAllText("../App/Views/Kit/SwitchBoardPurpleEnvelopeEdit.asp")

T.Assert InStr(viewSource, "Model.Kit.Status = ""Done""") > 0, "Expected the delivery paperwork button to remain gated by Done status."
T.Assert InStr(viewSource, "PrintDeliveryPaperwork") > 0, "Expected the delivery paperwork link target to remain in the view."
End Sub

Public Sub Test_KitController_Declares_PrintDeliveryPaperwork_Action(T)
dim controllerSource : controllerSource = ReadAllText("../App/Controllers/Kit/KitController.asp")
T.Assert InStr(controllerSource, "Public Sub PrintDeliveryPaperwork") > 0, "Expected KitController to expose the PrintDeliveryPaperwork action."
End Sub
End Class
%>

+ 401
- 0
_bmad-output/implementation-artifacts/tech-spec-print-delivery-paperwork-purple-envelope.md Прегледај датотеку

@@ -0,0 +1,401 @@
---
title: 'Print Delivery Paperwork for Purple Envelope Jobs'
slug: 'print-delivery-paperwork-purple-envelope'
created: '2026-04-01'
status: 'Implementation Complete'
stepsCompleted: [1, 2, 3, 4]
tech_stack: ['Classic ASP', 'VBScript', 'Access MDB (Jet/ACE)', 'ReportMan ActiveX', 'ADO', 'FSO', 'ASPUnit']
files_to_modify:
- 'Data/Migrations/Migration_21_Create_DeliveryLabelPage_Table.asp'
- 'App/ViewModels/KitViewModels.asp'
- 'App/DomainModels/KitRepository.asp'
- 'App/Controllers/Kit/KitController.asp'
- 'App/Views/Kit/SwitchBoardPurpleEnvelopeEdit.asp'
- 'Tests/TestCase_PurpleEnvelopeReport.asp'
- 'Data/Delivery_Labels.rep'
- 'Data/Delivery_PackingSlip.rep'
code_patterns: ['Controller GET action (parameterless Sub, reads QueryString)', 'Fresh ReportManX object per report export', 'Repository with DAL.BeginTransaction + DAL.Execute array params', 'Classic ASP migration class under Data/Migrations', 'HTML.LinkToExt for GET links']
test_patterns: ['ASPUnit DB-backed tests using disposable MDB copies', 'Manual IIS verification required for COM/ReportMan/FSO/network share', 'Boundary testing at 1100-label increments']
---

# Tech-Spec: Print Delivery Paperwork for Purple Envelope Jobs

**Created:** 2026-04-01

## Overview

### Problem Statement

After inkjet export completes and the ImportService sets a Purple Envelope kit to `Status = "Done"`, staff still need delivery paperwork to ship the job: shipping labels showing box counts and a packing slip for signed receipt. The Purple Envelope switchboard currently has no way to generate those documents.

### Solution

Add a `Print Delivery Paperwork` action to the Purple Envelope workflow. When a kit is in `Done` status, the edit screen will show a button that calls a new `KitController.PrintDeliveryPaperwork` GET action. That action will:

1. Reload the kit through `SwitchBoardPurpleEnvelopeEditFindById`.
2. Reject direct access unless the kit status is exactly `Done`.
3. Compute total shipping boxes with ceiling division by 1100 labels per box.
4. Build staged label-page rows in reverse box order, six labels per page.
5. Persist those rows into a new `DeliveryLabelPage` staging table.
6. Generate a labels PDF from `Data\Delivery_Labels.rep`.
7. Generate a packing slip PDF from `Data\Delivery_PackingSlip.rep`.
8. Save both PDFs into the existing export folder for the jurisdiction.
9. Remove staged rows after both files are successfully generated and moved.
10. Redirect back to `SwitchBoardPurpleEnvelopeEdit` with flash messaging.

### Scope

**In Scope:**
- New Access migration for `DeliveryLabelPage`
- New `DeliveryLabelPage_Class` view model
- New `KitRepository.SaveDeliveryLabelPages` and `KitRepository.DeleteDeliveryLabelPages`
- New `KitController.PrintDeliveryPaperwork` GET action
- New `Print Delivery Paperwork` button on `SwitchBoardPurpleEnvelopeEdit.asp`
- Reverse-order page building for any number of boxes, six labels per page
- Two new ReportMan templates and their required parameters/query contracts
- Overwrite-safe PDF output to the existing export folder
- ASPUnit coverage for staging-table persistence and source-level UI/controller guardrails

**Out of Scope:**
- Changing how kit status becomes `Done`
- Emailing, printing, or otherwise distributing the PDFs after generation
- Generalizing this into a reusable report-generation framework
- Changing existing label export behavior outside this Purple Envelope paperwork flow

## Context for Development

### Codebase Patterns

- `ImportService/TrackingDataImport.vbs` sets kit status to `Done` after inkjet export. The web app should treat that as the gate for paperwork generation, not redefine the lifecycle.
- `KitController.SwitchBoardPurpleEnvelopeEdit` already loads the exact header data this feature needs, including `JCode`, `Jurisdiction`, `JobNumber`, `Status`, and `LabelCount`.
- `App/Views/Kit/SwitchBoardPurpleEnvelopeEdit.asp` already conditionally shows UI based on `Model.Kit.Status`; the new button should follow that same pattern.
- `ExportTrackingLabels` in `KitController.asp` is the nearest existing ReportMan export example, including connection-string setup, overwrite behavior, and `FSO.MoveFile`.
- `MVC/activeXdepedancies.asp` exposes a shared `ReportManager`, but `HomeController.asp` shows that creating a fresh `Server.CreateObject("ReportMan.ReportManX")` instance is acceptable when isolated state is preferable.
- `MVC/lib.Data.asp` confirms `DAL.BeginTransaction`, `DAL.CommitTransaction`, and `DAL.RollbackTransaction` are available.
- Existing purple-envelope tests in `Tests/TestCase_PurpleEnvelopeReport.asp` already use disposable MDB copies and are the right place to add repository-level coverage for this feature.

### Files to Reference

| File | Purpose |
| ---- | ------- |
| `App/Controllers/Kit/KitController.asp` | Add `PrintDeliveryPaperwork`; reference `ExportTrackingLabels` for ReportMan + FSO export flow |
| `App/DomainModels/KitRepository.asp` | `SwitchBoardPurpleEnvelopeEditFindById` already exposes `LabelCount`, `JCode`, and `Jurisdiction` |
| `App/ViewModels/KitViewModels.asp` | Add `DeliveryLabelPage_Class` |
| `App/Views/Kit/SwitchBoardPurpleEnvelopeEdit.asp` | Add the `Done`-gated button |
| `Data/Migrations/Migration_20_Add_ColorId_To_InkjetRecords.asp` | Migration naming/style reference; next migration is `Migration_21_...` |
| `MVC/lib.Data.asp` | Confirms transaction and parameter-array behavior |
| `MVC/activeXdepedancies.asp` | Confirms ReportManX is already installed/used in the app |
| `Tests/TestCase_PurpleEnvelopeReport.asp` | Existing purple-envelope test fixture patterns to extend |

### Technical Decisions

1. **Use the existing Purple Envelope edit query.**
`SwitchBoardPurpleEnvelopeEditFindById` already returns the required header fields and the inkjet-record-derived `LabelCount`. No new count query is needed.

2. **Add a dedicated staging table.**
ReportMan should read normal rows from Access rather than trying to derive reverse-ordered page slots inside the `.rep` file.

```sql
CREATE TABLE [DeliveryLabelPage] (
[ID] COUNTER CONSTRAINT [PrimaryKey] PRIMARY KEY,
[KitID] LONG NOT NULL,
[PageNum] INTEGER NOT NULL,
[Label1] TEXT(500),
[Label2] TEXT(500),
[Label3] TEXT(500),
[Label4] TEXT(500),
[Label5] TEXT(500),
[Label6] TEXT(500)
);
```

3. **Repository owns staging-table lifecycle.**
`KitRepository.SaveDeliveryLabelPages` will delete existing rows for the kit and insert the new set inside one transaction. `KitRepository.DeleteDeliveryLabelPages` will remove rows after both PDFs succeed. The controller should not issue raw `DAL.Execute` cleanup for this feature.

4. **Page-building happens in VBScript, in reverse order.**
For `totalBoxes`, start at `boxNum = totalBoxes` and fill `Label1` through `Label6` before creating the next page row. That yields page 1 containing the highest box numbers first.

5. **Each PDF generation uses a fresh ReportManX instance.**
Use `Server.CreateObject("ReportMan.ReportManX")` separately for labels and packing slip. This avoids any parameter/template state bleed between the two exports.

6. **Direct URL access is guarded server-side.**
The button is hidden unless status is `Done`, but the controller must also reject non-`Done` requests with a warning flash and redirect. UI-only gating is not sufficient.

7. **Staging cleanup happens only after both PDFs are safely moved.**
If generation fails after staging rows are written, leave them in place. A subsequent run will replace them because `SaveDeliveryLabelPages` always deletes and re-inserts by `KitID`.

8. **Match existing export-folder naming.**
Use the same `ExportDirectory & JCode & "-" & Jurisdiction & "\"` pattern already used by `ExportTrackingLabels`. Do not introduce new filename sanitization behavior in this feature.

9. **Label text format is fixed.**
Each populated label slot is multiline text:

```
{Jurisdiction}
Box {X} of {TotalBoxes}
Total Printed {InkjetCount}
Job# {JobNumber}
```

Empty slots on the last page are `""`.

10. **Output filenames are deterministic.**
- Labels PDF: `{JCode}-{Jurisdiction}_delivery_labels.pdf`
- Packing slip PDF: `{JCode}-{Jurisdiction}_delivery_packing_slip.pdf`

## Implementation Plan

### Tasks

- [x] **Task 1: Add the `DeliveryLabelPage` migration**

File: `Data/Migrations/Migration_21_Create_DeliveryLabelPage_Table.asp`

```vbscript
<%
Class Migration_21_Create_DeliveryLabelPage_Table
Public Migration

Public Sub Up
Migration.Do "CREATE TABLE [DeliveryLabelPage] (" & _
"[ID] COUNTER CONSTRAINT [PrimaryKey] PRIMARY KEY, " & _
"[KitID] LONG NOT NULL, " & _
"[PageNum] INTEGER NOT NULL, " & _
"[Label1] TEXT(500), " & _
"[Label2] TEXT(500), " & _
"[Label3] TEXT(500), " & _
"[Label4] TEXT(500), " & _
"[Label5] TEXT(500), " & _
"[Label6] TEXT(500));"
End Sub

Public Sub Down
Migration.Do "DROP TABLE [DeliveryLabelPage];"
End Sub
End Class

Migrations.Add "Migration_21_Create_DeliveryLabelPage_Table"
%>
```

- [x] **Task 2: Add the staging-row view model and repository methods**

Files:
- `App/ViewModels/KitViewModels.asp`
- `App/DomainModels/KitRepository.asp`

Add:

```vbscript
Class DeliveryLabelPage_Class
Public PageNum
Public Label1
Public Label2
Public Label3
Public Label4
Public Label5
Public Label6
End Class
```

Add repository methods near the end of `KitRepository_Class`:

```vbscript
Public Sub SaveDeliveryLabelPages(ByVal kitId, ByVal pages)
dim sql, pageIt, page
sql = "INSERT INTO [DeliveryLabelPage] ([KitID],[PageNum],[Label1],[Label2],[Label3],[Label4],[Label5],[Label6]) VALUES (?,?,?,?,?,?,?,?)"

DAL.BeginTransaction
On Error Resume Next

DAL.Execute "DELETE FROM [DeliveryLabelPage] WHERE [KitID] = ?", CLng(kitId)

set pageIt = pages.Iterator
Do While Err.Number = 0 And pageIt.HasNext
set page = pageIt.GetNext()
DAL.Execute sql, Array(CLng(kitId), page.PageNum, page.Label1, page.Label2, page.Label3, page.Label4, page.Label5, page.Label6)
Loop

If Err.Number <> 0 Then
dim errNumber : errNumber = Err.Number
dim errDescription : errDescription = Err.Description
DAL.RollbackTransaction
On Error GoTo 0
Err.Raise errNumber, "KitRepository_Class.SaveDeliveryLabelPages", errDescription
End If

On Error GoTo 0
DAL.CommitTransaction
End Sub

Public Sub DeleteDeliveryLabelPages(ByVal kitId)
DAL.Execute "DELETE FROM [DeliveryLabelPage] WHERE [KitID] = ?", CLng(kitId)
End Sub
```

- [x] **Task 3: Add `PrintDeliveryPaperwork` to `KitController`**

File: `App/Controllers/Kit/KitController.asp`

Add a new parameterless GET action after `SwitchBoardPurpleEnvelopeEdit` and before `Index`.

Implementation requirements:
- Read `Id` from `Request.QueryString("Id")`
- Load the kit through `KitRepository.SwitchBoardPurpleEnvelopeEditFindById`
- If status is not `Done`, set `Flash.Warning` and redirect back to `SwitchBoardPurpleEnvelopeEdit`
- If `LabelCount <= 0`, set `Flash.Warning` and redirect
- Verify both `.rep` files exist before writing staging rows
- Create the export folder if missing
- Build a `LinkedList_Class` of `DeliveryLabelPage_Class` rows in reverse order
- Persist rows through `KitRepository.SaveDeliveryLabelPages`
- Generate labels PDF with a fresh local `ReportMan.ReportManX` object using `PBKITID`
- Generate packing slip PDF with a second fresh local `ReportMan.ReportManX` object using parameters:
- `PJURISDICTION`
- `PJOB_NUMBER`
- `PTOTAL_PRINTED`
- `PTOTAL_BOXES`
- Delete any existing final PDFs before moving the temp outputs into place
- Call `KitRepository.DeleteDeliveryLabelPages` only after both PDFs succeed
- Set `Flash.Success` and redirect back to `SwitchBoardPurpleEnvelopeEdit`

Concrete page-build algorithm:

```vbscript
If inkjetCount > 0 Then
totalBoxes = Int((inkjetCount + 1099) / 1100)
Else
totalBoxes = 0
End If

set pages = new LinkedList_Class
boxNum = totalBoxes
pageNum = 1

Do While boxNum >= 1
set page = new DeliveryLabelPage_Class
page.PageNum = pageNum

For slot = 1 To 6
labelText = ""
If boxNum >= 1 Then
labelText = jurisdiction & vbCrLf & _
"Box " & boxNum & " of " & totalBoxes & vbCrLf & _
"Total Printed " & inkjetCount & vbCrLf & _
"Job# " & jobNumber
boxNum = boxNum - 1
End If

Select Case slot
Case 1 : page.Label1 = labelText
Case 2 : page.Label2 = labelText
Case 3 : page.Label3 = labelText
Case 4 : page.Label4 = labelText
Case 5 : page.Label5 = labelText
Case 6 : page.Label6 = labelText
End Select
Next

pages.Push page
pageNum = pageNum + 1
Loop
```

Connection-string and export behavior should mirror `ExportTrackingLabels`, but use local report objects:

```vbscript
dim labelsReport : set labelsReport = Server.CreateObject("ReportMan.ReportManX")
dim slipReport : set slipReport = Server.CreateObject("ReportMan.ReportManX")
```

- [x] **Task 4: Add the `Done`-gated button to the Purple Envelope edit view**

File: `App/Views/Kit/SwitchBoardPurpleEnvelopeEdit.asp`

Insert this above the existing `Ready To Assign STIDS` block so it is visible when the job is already complete:

```asp
<% If Model.Kit.Status = "Done" Then %>
<p>
<%= HTML.LinkToExt("<i class='glyphicon glyphicon-print'></i> Print Delivery Paperwork", "Kit", "PrintDeliveryPaperwork", Array("Id", Model.Kit.ID), Array("class", "btn btn-primary")) %>
</p>
<% End If %>
```

- [x] **Task 5: Extend ASPUnit coverage**

File: `Tests/TestCase_PurpleEnvelopeReport.asp`

Add:
- A DB-backed test that seeds a Purple Envelope kit, calls `SaveDeliveryLabelPages`, and verifies inserted row count and label values
- A DB-backed test that calls `SaveDeliveryLabelPages` twice for the same kit and proves the second run fully replaces the first
- A DB-backed test for `DeleteDeliveryLabelPages`
- A source-level guard test asserting the view contains the `Model.Kit.Status = "Done"` condition and `PrintDeliveryPaperwork` link
- A source-level guard test asserting `KitController.asp` defines `Public Sub PrintDeliveryPaperwork`

- [x] **Task 6: Create the two ReportMan templates**

Files:
- `Data/Delivery_Labels.rep`
- `Data/Delivery_PackingSlip.rep`

`Delivery_Labels.rep`
- Connection: `TRACKINGKITLABELS`
- Parameter: `PBKITID`
- Query:
`SELECT Label1, Label2, Label3, Label4, Label5, Label6 FROM DeliveryLabelPage WHERE KitID = [PBKITID] ORDER BY PageNum`
- Layout: one detail row per page, with six multiline label areas arranged 2 columns by 3 rows

`Delivery_PackingSlip.rep`
- Parameters only:
- `PJURISDICTION`
- `PJOB_NUMBER`
- `PTOTAL_PRINTED`
- `PTOTAL_BOXES`
- Layout: single-page packing slip with jurisdiction, job number, totals, signature line, and date line

### Acceptance Criteria

- [ ] **AC1 - Button visibility:** Given a Purple Envelope kit with `Status = "Done"`, when `SwitchBoardPurpleEnvelopeEdit` renders, then the `Print Delivery Paperwork` button is visible.
- [ ] **AC2 - Button hidden when not done:** Given a Purple Envelope kit whose status is anything other than `Done`, when the page renders, then the button is not visible.
- [ ] **AC3 - Direct route guard:** Given a user browses directly to `PrintDeliveryPaperwork` for a kit whose status is not `Done`, when the action runs, then it redirects back with a warning flash and produces no PDFs.
- [ ] **AC4 - Exact 1100 boundary:** Given a kit with exactly 1100 inkjet records, when paperwork is generated, then `totalBoxes = 1` and the staged row has `Label1 = "Box 1 of 1"` with `Label2` through `Label6` blank.
- [ ] **AC5 - One over boundary:** Given a kit with 1101 inkjet records, when paperwork is generated, then `totalBoxes = 2` and the staged row contains `Label1 = "Box 2 of 2"` and `Label2 = "Box 1 of 2"`.
- [ ] **AC6 - Multi-page reverse ordering:** Given a kit with 7701 inkjet records, when paperwork is generated, then two staged rows are written and page 1 contains boxes 7 through 2 while page 2 contains box 1 only.
- [ ] **AC7 - Label text contract:** Given any populated label slot, when its text is inspected, then it includes jurisdiction, `Box X of Y`, `Total Printed N`, and `Job# N` on separate lines.
- [ ] **AC8 - Labels PDF output:** Given a kit with `JCode = "01234"` and `Jurisdiction = "Anytown"`, when paperwork generation succeeds, then `01234-Anytown_delivery_labels.pdf` exists in `ExportDirectory\01234-Anytown\`.
- [ ] **AC9 - Packing slip PDF output:** Given the same kit, when paperwork generation succeeds, then `01234-Anytown_delivery_packing_slip.pdf` exists in the same export folder.
- [ ] **AC10 - Overwrite behavior:** Given one or both delivery PDFs already exist, when paperwork is generated again, then the existing files are replaced without error.
- [ ] **AC11 - Success redirect:** Given both PDFs are generated and moved successfully, when the action completes, then the user is redirected back to `SwitchBoardPurpleEnvelopeEdit` with a success flash.
- [ ] **AC12 - Staging-row replacement and cleanup:** Given existing `DeliveryLabelPage` rows already exist for the kit, when paperwork is generated, then those rows are replaced by the new set and removed after both PDFs succeed.
- [ ] **AC13 - Missing template failure is handled:** Given either `.rep` file is missing, when the action runs, then the user receives a warning flash and the request does not crash with a 500.
- [ ] **AC14 - Packing slip parameters stay isolated:** Given paperwork generation runs end-to-end, when the packing slip PDF is inspected, then it shows the expected jurisdiction and job number rather than stale parameters from the labels export.

## Additional Context

### Dependencies

- `ReportMan.ReportManX` ActiveX installed on the IIS host
- `FSO` and `DAL` globals already loaded through `App/include_all.asp`
- `ExportDirectory` and `dev` from `App/app.config.asp`
- `LinkedList_Class` from the shared MVC libraries
- `Delivery_Labels.rep` and `Delivery_PackingSlip.rep` present in `Data\`
- `DeliveryLabelPage` migration applied to the active MDB before use

### Testing Strategy

- Run ASPUnit through `Tests/Test_All.asp` after adding the repository and source-guard tests.
- Add DB-backed tests using the same disposable MDB pattern already present in `Tests/TestCase_PurpleEnvelopeReport.asp`.
- Perform manual IIS verification for:
- status `Done` button visibility
- direct-route guard for non-`Done` kits
- 1100 / 1101 / 6600 / 6601 label-count boundaries
- overwrite behavior when PDFs already exist
- missing-template warning behavior
- correct output in both dev and prod-style connection-string branches
- final export folder/file placement on the configured filesystem share

### Notes

- This spec is ready for implementation. The next BMAD step for this artifact is `Quick Dev` using `/bmad-bmm-quick-dev` in a fresh context.
- The report templates are the only manual-designer portion of the work. Everything else is ordinary Classic ASP / VBScript / Access code and test coverage.
- Keeping fresh ReportManX instances per PDF is the main design choice that removes the last meaningful ambiguity from the earlier review draft.

Loading…
Откажи
Сачувај

Powered by TurnKey Linux.