Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/extraScripts/migration/holoo2hesabix/UI/TransferPanel.vb
Babak Alizadeh a5875e7a3a Release Holoo2Hesabix 1.1.0 with production-ready accounting migration.
Harden Holoo-to-Hesabix document partition/mapping, sample E2E tooling, remove hardcoded SQL credentials from scripts, fix income AR account 10401, and publish Setup MSI 1.1.0.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 15:56:40 +03:30

271 lines
12 KiB
VB.net

Imports System.Threading
Friend Class TransferPanel
Inherits UserControl
Private ReadOnly _session As MigrationSession
Private ReadOnly _api As HesabixApiClient
Private ReadOnly _baseTransfer As New BaseDataTransferService()
Private ReadOnly _docTransfer As New DocumentTransferService()
Private ReadOnly _progress As ModernProgressBar
Private ReadOnly _lblModule As Label
Private ReadOnly _txtLog As TextBox
Private ReadOnly _logCard As Panel
Private ReadOnly _btnStart As Button
Private ReadOnly _btnCancel As Button
Private ReadOnly _chkReset As CheckBox
Private ReadOnly _checkpointBanner As ContextBanner
Private _cts As CancellationTokenSource
Private _running As Boolean
Public Sub New(session As MigrationSession, api As HesabixApiClient)
_session = session
_api = api
DoubleBuffered = True
BackColor = AppTheme.BgApp
RightToLeft = RightToLeft.Yes
Dock = DockStyle.Fill
Dim header = PageHeader.Create(
"انتقال اطلاعات",
"پایه + اسناد سال‌به‌سال. در صورت قطع، از checkpoint ادامه می‌یابد.")
_chkReset = New CheckBox() With {
.Text = "شروع از صفر (پاک کردن checkpoint)",
.AutoSize = True,
.Name = "chkReset"
}
AppTheme.StyleCheckBox(_chkReset)
_chkReset.ForeColor = AppTheme.TextSecondary
_btnStart = New Button() With {
.Text = "شروع / ادامه انتقال",
.Size = New Size(180, AppTheme.FieldHeight),
.RightToLeft = RightToLeft.Yes,
.Name = "btnStart"
}
AppTheme.StylePrimaryButton(_btnStart)
AddHandler _btnStart.Click, AddressOf OnStartClick
_btnCancel = New Button() With {
.Text = "توقف",
.Size = New Size(100, AppTheme.FieldHeight),
.Enabled = False,
.RightToLeft = RightToLeft.Yes,
.Name = "btnCancel"
}
AppTheme.StyleSecondaryButton(_btnCancel)
AddHandler _btnCancel.Click, AddressOf OnCancelClick
_lblModule = New Label() With {
.AutoSize = True,
.Font = AppTheme.FontUiBold,
.ForeColor = AppTheme.TextPrimary,
.RightToLeft = RightToLeft.Yes,
.Text = "آماده",
.Name = "lblModule"
}
_progress = New ModernProgressBar() With {
.Height = 28,
.Maximum = 100,
.Value = 0,
.Caption = "",
.Name = "progress"
}
_logCard = New Panel() With {
.BackColor = Color.Transparent,
.RightToLeft = RightToLeft.Yes,
.Padding = New Padding(14),
.Name = "logCard"
}
AddHandler _logCard.Paint, Sub(s, e)
Dim r As New Rectangle(0, 0, _logCard.Width - 1, _logCard.Height - 1)
AppTheme.DrawRoundedRect(e.Graphics, r, 14, Color.FromArgb(15, 23, 42), Color.FromArgb(30, 41, 59), 1.0F)
End Sub
_txtLog = New TextBox() With {
.Multiline = True,
.ReadOnly = True,
.ScrollBars = ScrollBars.Vertical,
.Font = AppTheme.FontStep,
.BackColor = Color.FromArgb(15, 23, 42),
.ForeColor = Color.FromArgb(226, 232, 240),
.BorderStyle = BorderStyle.None,
.Dock = DockStyle.Fill,
.RightToLeft = RightToLeft.Yes,
.Name = "txtLog"
}
_logCard.Controls.Add(_txtLog)
_checkpointBanner = New ContextBanner() With {.Width = 520, .Name = "checkpointBanner"}
_checkpointBanner.SetStatus("", ContextBanner.BannerTone.Neutral)
Controls.Add(header.Item1)
Controls.Add(header.Item2)
Controls.Add(_chkReset)
Controls.Add(_btnStart)
Controls.Add(_btnCancel)
Controls.Add(_lblModule)
Controls.Add(_progress)
Controls.Add(_logCard)
Controls.Add(_checkpointBanner)
AddHandler _baseTransfer.ProgressChanged, AddressOf OnTransferProgress
AddHandler _docTransfer.ProgressChanged, AddressOf OnTransferProgress
AddHandler Resize, AddressOf OnPanelResize
OnPanelResize(Me, EventArgs.Empty)
AppTheme.ApplyRtlTree(Me, False)
OnPanelResize(Me, EventArgs.Empty)
End Sub
Private Sub OnPanelResize(sender As Object, e As EventArgs)
Dim w = ClientSize.Width
Dim m = AppTheme.PageMargin
Dim title = Controls("title")
Dim subtitle = Controls("subtitle")
If title IsNot Nothing Then AppTheme.PlaceFromRight(title, w, m, 18)
If subtitle IsNot Nothing Then AppTheme.PlaceFromRight(subtitle, w, m, 52)
AppTheme.PlaceFromRight(_chkReset, w, m, 92)
AppTheme.PlaceFromRight(_btnStart, w, m, 128)
AppTheme.PlaceFromRight(_btnCancel, w, m + _btnStart.Width + 12, 128)
AppTheme.PlaceFromRight(_lblModule, w, m, 184)
_progress.Width = Math.Max(640, w - m * 2)
AppTheme.PlaceFromRight(_progress, w, m, 214)
_logCard.Width = _progress.Width
_logCard.Height = Math.Max(180, ClientSize.Height - 320)
AppTheme.PlaceFromRight(_logCard, w, m, 252)
_checkpointBanner.Width = Math.Max(400, w - m * 2)
AppTheme.PlaceFromRight(_checkpointBanner, w, m, _logCard.Bottom + 10)
End Sub
Public Sub Prepare()
Dim store As New CheckpointStore(_session.SelectedBusiness.Id, _session.SelectedDatabase)
_checkpointBanner.SetStatus("مسیر checkpoint: " & store.FilePath, ContextBanner.BannerTone.Neutral)
OnPanelResize(Me, EventArgs.Empty)
If Not _running Then
AppendLog("آماده برای شروع یا ادامه انتقال.")
End If
End Sub
Private Async Sub OnStartClick(sender As Object, e As EventArgs)
If _running Then Return
If _session.SelectedBusiness Is Nothing OrElse Not _session.CanProceedFromHolooSql Then
MessageBox.Show(Me, "ابتدا حسابیکس و دیتابیس هلو را کامل کنید.", "شروع ممکن نیست",
MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, AppTheme.MsgRtl)
Return
End If
Dim modules = If(_session.SelectedModules, MigrationModuleInfo.GetAllModules()).
Where(Function(x) x.Selected AndAlso x.Enabled).
Select(Function(x) x.ModuleKey).ToList()
If modules.Count = 0 Then
MessageBox.Show(Me, "هیچ بخشی انتخاب نشده است.", "شروع ممکن نیست",
MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, AppTheme.MsgRtl)
Return
End If
Dim currencyId = If(_session.Preflight IsNot Nothing, _session.Preflight.HesabixCurrencyId, 0)
If currencyId <= 0 Then
MessageBox.Show(Me, "شناسه ارز کسب‌وکار مشخص نیست. ابتدا بازبینی تطبیقی را اجرا کنید.", "شروع ممکن نیست",
MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, AppTheme.MsgRtl)
Return
End If
Dim hasDocs = modules.Any(Function(m) MigrationModuleInfo.IsDocumentModule(m))
Dim skipOb = hasDocs
If hasDocs AndAlso Not _session.SarfaslProfileLocked Then
MessageBox.Show(Me, "برای انتقال اسناد باید در مرحله بازبینی، پروفایل نگاشت سرفصل را قفل کنید.", "شروع ممکن نیست",
MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, AppTheme.MsgRtl)
Return
End If
If hasDocs AndAlso _session.SarfaslProfile IsNot Nothing AndAlso _session.SarfaslProfile.CriticalUnmappedCount > 0 Then
MessageBox.Show(Me, "سرفصل بحرانی بدون نگاشت باقی است؛ انتقال اسناد متوقف است.", "شروع ممکن نیست",
MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, AppTheme.MsgRtl)
Return
End If
_running = True
_btnStart.Enabled = False
_btnCancel.Enabled = True
_chkReset.Enabled = False
CancelPending()
_cts = New CancellationTokenSource()
AppendLog("=== شروع انتقال ===")
If skipOb Then AppendLog("حالت Full History: مانده افتتاحیه اشخاص/کالا جداگانه ارسال نمی‌شود.")
Try
Dim path = Await _baseTransfer.RunAsync(
_session, _api, modules, currencyId, _chkReset.Checked, skipOb, _cts.Token).ConfigureAwait(True)
AppendLog("پایان اطلاعات پایه. Checkpoint: " & path)
If hasDocs Then
AppendLog("=== شروع انتقال اسناد (سال‌به‌سال) ===")
path = Await _docTransfer.RunAsync(
_session, _api, modules, currencyId, False, _cts.Token).ConfigureAwait(True)
AppendLog("پایان اسناد. Checkpoint: " & path)
End If
_lblModule.Text = "پایان یافت"
_lblModule.ForeColor = AppTheme.Success
_progress.Caption = "پایان یافت"
MessageBox.Show(Me, "انتقال به پایان رسید (موارد خطادار در لاگ و checkpoint ثبت شده‌اند).", "انتقال",
MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, AppTheme.MsgRtl)
Catch ex As OperationCanceledException
AppendLog("انتقال توسط کاربر متوقف شد. اجرای بعدی از checkpoint ادامه می‌دهد.")
_lblModule.Text = "متوقف شد"
_lblModule.ForeColor = AppTheme.Warning
_progress.Caption = "متوقف شد"
Catch ex As Exception
AppendLog("خطای کلی: " & ex.Message)
_lblModule.Text = "خطا"
_lblModule.ForeColor = AppTheme.Danger
_progress.Caption = "خطا"
AsyncUi.ShowError(Me, "خطا در انتقال", ex)
Finally
_running = False
_btnStart.Enabled = True
_btnCancel.Enabled = False
_chkReset.Enabled = True
End Try
End Sub
Private Sub OnCancelClick(sender As Object, e As EventArgs)
If _cts IsNot Nothing Then _cts.Cancel()
End Sub
Private Sub OnTransferProgress(sender As Object, e As TransferProgressEventArgs)
If InvokeRequired Then
BeginInvoke(New Action(Of Object, TransferProgressEventArgs)(AddressOf OnTransferProgress), sender, e)
Return
End If
_lblModule.Text = e.ModuleTitle
_lblModule.ForeColor = If(e.IsError, AppTheme.Danger, AppTheme.TextPrimary)
If e.Total > 0 Then
_progress.Maximum = Math.Max(e.Total, 1)
_progress.Value = Math.Min(e.Current, _progress.Maximum)
_progress.Caption = e.Current.ToString("N0") & " / " & e.Total.ToString("N0")
Else
_progress.Caption = e.ModuleTitle
End If
AppendLog("[" & e.ModuleTitle & "] " & e.Message)
OnPanelResize(Me, EventArgs.Empty)
End Sub
Private Sub AppendLog(text As String)
If _txtLog.TextLength > 0 Then _txtLog.AppendText(Environment.NewLine)
_txtLog.AppendText(DateTime.Now.ToString("HH:mm:ss") & " " & text)
End Sub
Private Sub CancelPending()
If _cts IsNot Nothing Then
_cts.Dispose()
_cts = Nothing
End If
End Sub
End Class