1994 lines
78 KiB
C#
1994 lines
78 KiB
C#
///
|
|
/// Copyright (c) 2016-2022 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using FluentNHibernate.Cfg;
|
|
using FluentNHibernate.Cfg.Db;
|
|
using log4net;
|
|
using NHibernate;
|
|
using SharedDatabase;
|
|
using SharedDatabase.Entities;
|
|
using SharedDatabase.Forms;
|
|
using Workplace.Resources;
|
|
|
|
namespace Workplace
|
|
{
|
|
public partial class WorkplaceDlg : Form
|
|
{
|
|
static readonly ILog log = LogManager.GetLogger(typeof(WorkplaceDlg));
|
|
|
|
[DllImport("User32.dll")] public static extern Int32 SetForegroundWindow(int hWnd);
|
|
|
|
public const int NrGeneratorIx = 0; /// BaseNr1 and CurrentNr1 are used to generate and print serial numbers
|
|
|
|
const int ErrorBeepFrequency = 500; /// Hz
|
|
const int ErrorBeepDuration = 1000; /// ms
|
|
|
|
public int ExtraBatteryLifetime; /// In months, default = 0
|
|
|
|
public ISessionFactory SessionFactory;
|
|
public ISession dbSession;
|
|
|
|
Common.Forms.ModelessForm modelessForm;
|
|
|
|
public IList<OrderInfo> AllOrders; /// All orders including the finished ones
|
|
IList<OrderInfo> orders; /// New and active orders from the database
|
|
IList<Process> workflows; /// Workflows from the database
|
|
WPlaceRegistrationMgmt wplaceRegistration;
|
|
|
|
Timer runDeviceTimer; /// Timer for regular 1 second ticks
|
|
DateTime lastActivity; /// Timestamp of the last users activity (OnBarcodeReceived, OnFocusPressed, etc.)
|
|
DateTime lastLoginTime; /// Timestamp of the last user login
|
|
bool isLoggedOut;
|
|
|
|
/// This object processes records (=files) from a thirdparty program and extract reference part codes
|
|
RecordProcessing.RecordProcessing recordProcessing;
|
|
|
|
/// Currently displayed process and workstep
|
|
public OrderInfo CurrentOrder; /// Currently used order
|
|
public Process CurrentWorkflow; /// Currently used process
|
|
public Workstep CurrentWorkstep; /// Currently used workstep
|
|
IList<Workstep> workstepsOfTheCurrentWorkflow;
|
|
|
|
/// ix=0, orderNr=1
|
|
string[] predefinedOrders = new[] { Strings.none };
|
|
|
|
/// Previous workstep verification
|
|
Workstep verifiedWorkstep;
|
|
Part verifiedPart; /// Applicable when verifyReferencePart == false
|
|
bool verifyReferencePart;
|
|
|
|
/// Items to be scanned/filled in
|
|
IList<ICheckItem> komponenty;
|
|
IList<ICheckItem> palety;
|
|
|
|
bool isSNPrinting { get { return komponenty != null && komponenty.Count == 1 && komponenty[0] is CheckItems.SNGeneratorPrinter; } }
|
|
|
|
bool loadedOnce;
|
|
bool supressUINotifications;
|
|
|
|
PartError errorFlag;
|
|
|
|
public static void BuildSchema(NHibernate.Cfg.Configuration config)
|
|
{
|
|
/// This NHibernate tool takes a configuration (with mapping info in)
|
|
/// and exports a database schema from it
|
|
new NHibernate.Tool.hbm2ddl.SchemaExport(config).SetOutputFile("db_schema");
|
|
}
|
|
|
|
public WorkplaceDlg()
|
|
{
|
|
try
|
|
{
|
|
string culture = Program.LocalSettings.Language.Replace('_', '-');
|
|
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(culture);
|
|
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(culture);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
string msg = exc.Message;
|
|
MessageBox.Show("Selected language is not supported.\nUsing English.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
|
|
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en");
|
|
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");
|
|
}
|
|
|
|
modelessForm = new Common.Forms.ModelessForm(Strings.Loading_configuration_from_a_database);
|
|
new System.Threading.Thread(() => Application.Run(modelessForm)).Start();
|
|
|
|
InitializeComponent();
|
|
|
|
supressUINotifications = true;
|
|
ManageCheckGroupBox(batchesCheckBox, batchesGroupBox);
|
|
|
|
wplaceRegistration = new WPlaceRegistrationMgmt();
|
|
komponenty = new List<ICheckItem>();
|
|
palety = new List<ICheckItem>();
|
|
|
|
do
|
|
{
|
|
dbSession = null;
|
|
orders = null;
|
|
AllOrders = null;
|
|
workflows = null;
|
|
|
|
try
|
|
{
|
|
SessionFactory = Fluently.Configure()
|
|
.Database(MySQLConfiguration.Standard.ConnectionString(Program.LocalSettings.ConnectionString))
|
|
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<SharedDatabase.Entities.Process>())
|
|
.ExposeConfiguration(BuildSchema).BuildSessionFactory();
|
|
|
|
dbSession = SessionFactory.OpenSession();
|
|
orders = ReadOrders(dbSession);
|
|
AllOrders = ReadOrders(dbSession, false);
|
|
workflows = ReadReleasedActiveProcesses(dbSession);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
DialogResult rslt = MessageBox.Show(Strings.Opening_database_failed +
|
|
Environment.NewLine + Environment.NewLine +
|
|
exc.Message +
|
|
Environment.NewLine + Environment.NewLine +
|
|
Strings.Do_you_want_to_change_settings,
|
|
Strings.Warning,
|
|
MessageBoxButtons.YesNo,
|
|
MessageBoxIcon.Exclamation);
|
|
|
|
if (rslt != DialogResult.Yes)
|
|
{
|
|
if (modelessForm != null) modelessForm.CloseForm();
|
|
throw new Common.QuitAppException(Strings.Opening_database_failed);
|
|
}
|
|
}
|
|
|
|
if (dbSession == null || orders == null ||
|
|
AllOrders == null || workflows == null)
|
|
{
|
|
var dr = Configure();
|
|
if (dr != DialogResult.OK)
|
|
{
|
|
if (modelessForm != null) modelessForm.CloseForm();
|
|
throw new Common.QuitAppException(Strings.Opening_database_failed);
|
|
}
|
|
}
|
|
}
|
|
while (dbSession == null || orders == null ||
|
|
AllOrders == null || workflows == null);
|
|
|
|
BarcodeReceivedHandler += delegate(object sndr, BarcodeReceivedEventArgs args)
|
|
{
|
|
if (InvokeRequired) { Invoke(new EventHandler<BarcodeReceivedEventArgs>(BarcodeReceived), sndr, args); }
|
|
else { BarcodeReceived(sndr, args); }
|
|
};
|
|
|
|
FocusPressedHandler += delegate(object sndr, FocusPressedEventArgs args)
|
|
{
|
|
if (InvokeRequired) { Invoke(new EventHandler<FocusPressedEventArgs>(FocusPressed), sndr, args); }
|
|
else { FocusPressed(sndr, args); }
|
|
};
|
|
|
|
ColorFlashHandler += delegate(object sender, ColorFlashEventArgs args)
|
|
{
|
|
if (InvokeRequired) { Invoke(new EventHandler<ColorFlashEventArgs>(OnColorFlash), sender, args); }
|
|
else OnColorFlash(sender, args);
|
|
};
|
|
|
|
workplaceTextBox.Text = Program.LocalSettings.WorkplaceId;
|
|
|
|
workerTextBox.Text = Common.CurrentUser.UserName();
|
|
lastLoginTime = DateTime.Now;
|
|
isLoggedOut = false;
|
|
|
|
ResetIdleTime();
|
|
|
|
/// Timer for regular 1 second ticks
|
|
runDeviceTimer = new System.Windows.Forms.Timer();
|
|
runDeviceTimer.Interval = Const.Interval;
|
|
runDeviceTimer.Tick += new EventHandler(runDeviceTimer_Tick);
|
|
runDeviceTimer.Start();
|
|
|
|
|
|
///
|
|
/// Activate processing of records (log files) created by a thirdparty program
|
|
///
|
|
if (Program.LocalSettings.RecordProcessing == RecordProcessing.RecordType.CommTest)
|
|
{
|
|
recordProcessing = new RecordProcessing.RecordProcessing(RecordProcessing.RecordType.CommTest,
|
|
RecordProcessing.RecordPostproc.None,
|
|
"C:\\iPerl\\LogFiles\\CommTester", true, "*.log");
|
|
}
|
|
else
|
|
{
|
|
recordProcessing = null;
|
|
}
|
|
|
|
if (recordProcessing != null)
|
|
{
|
|
recordProcessing.SubmitRecordHandler += delegate(object sender, RecordProcessing.SubmitRecordEventArgs args)
|
|
{
|
|
if (InvokeRequired)
|
|
{
|
|
Invoke(new EventHandler<RecordProcessing.SubmitRecordEventArgs>(SubmitRecordFromThirdpartyTester), sender, args);
|
|
}
|
|
else
|
|
{
|
|
SubmitRecordFromThirdpartyTester(sender, args);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Submits a reference part code from a record from a 3-rd party program
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="args">Argument containing the reference part s/n</param>
|
|
void SubmitRecordFromThirdpartyTester(object sender, RecordProcessing.SubmitRecordEventArgs args)
|
|
{
|
|
if ((komponenty != null) && (komponenty.Count >= 1))
|
|
{
|
|
if (komponenty.Count >= 2) this.Activate(); /// Activate this window if there is 2nd code to scan
|
|
|
|
komponenty[0].SubmitCode(args.Record.SN); /// Submit the reference part code
|
|
|
|
//this.BringToFront(); /// 1 Tested: Brings window to the top only, does not activate the window
|
|
|
|
this.WindowState = FormWindowState.Minimized; /// 2 Works OK !!!
|
|
this.Show();
|
|
this.WindowState = FormWindowState.Normal;
|
|
|
|
//SetForegroundWindow(Handle.ToInt32()); /// 3 Should work as well
|
|
|
|
//this.Activate(); /// 4 Tested: Does not activate the window
|
|
//this.Focus();
|
|
}
|
|
}
|
|
|
|
|
|
private void WorkplaceDlg_Load(object sender, EventArgs e)
|
|
{
|
|
Localize();
|
|
|
|
CurrentOrder = null;
|
|
CurrentWorkflow = null;
|
|
CurrentWorkstep = null;
|
|
UpdateOrderCombo(orders, string.Empty);
|
|
workstepComboBox.Text = Program.LocalSettings.LastWorkstep;
|
|
if (UpdateWorkflowCombo(workflows, Program.LocalSettings.LastWorkflow))
|
|
{
|
|
if (UpdateWorkstepCombo(CurrentWorkflow, Program.LocalSettings.LastWorkstep))
|
|
{
|
|
UpdateItems();
|
|
}
|
|
}
|
|
|
|
if (modelessForm != null) modelessForm.CloseForm();
|
|
loadedOnce = true;
|
|
supressUINotifications = false;
|
|
|
|
orderComboBox.Focus();
|
|
}
|
|
|
|
|
|
void Localize()
|
|
{
|
|
orderLabel.Text = string.Format("{0}:", Strings.Order);
|
|
workflowLabel.Text = string.Format("{0}:", Strings.Workflow);
|
|
workstepLabel.Text = string.Format("{0}:", Strings.Workflow_step);
|
|
workerLabel.Text = string.Format("{0}:", Strings.Production_operator);
|
|
workplaceLabel.Text = string.Format("{0}:", Strings.Workplace);
|
|
logoutButton.Text = Strings.Exchange_of_operator;
|
|
configureButton.Text = Strings.Configure;
|
|
groupBox2.Text = Strings.Codes_of_components;
|
|
batchesCheckBox.Text = Strings.Codes_of_batches;
|
|
clearButton.Text = Strings.New_codes;
|
|
resetErrorStateButton.Text = Strings.Clear_errors;
|
|
failedCheckBox.Text = Strings.Failure;
|
|
saveAllCodesButton.Text = Strings.Save;
|
|
completedGroupBox.Text = Strings.Completed;
|
|
targetGroupBox.Text = Strings.Target;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Read released-active processes from the database.
|
|
/// </summary>
|
|
/// <param name="session">Production tracing DB session</param>
|
|
/// <returns>A list of processes (success) or null (failure)</returns>
|
|
private IList<Process> ReadReleasedActiveProcesses(ISession session)
|
|
{
|
|
try
|
|
{
|
|
return session.QueryOver<Process>()
|
|
.Where(x => (x.ReleaseStatus == ReleaseStatus.In_preparation ||
|
|
x.ReleaseStatus == ReleaseStatus.ToBeApproved ||
|
|
x.ReleaseStatus == ReleaseStatus.ReleasedActive ||
|
|
x.ReleaseStatus == ReleaseStatus.Released))
|
|
.OrderBy(x => x.Name).Asc
|
|
.List();
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
log.ErrorFormat("Failed to load processes from the tracing DB: {0}", exc.Message);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
IList<OrderInfo> ReadOrders(ISession session, bool newOrActiveOrdersOnly = true)
|
|
{
|
|
try
|
|
{
|
|
if (newOrActiveOrdersOnly)
|
|
{
|
|
var list = session.QueryOver<OrderInfo>()
|
|
.Where(x => (x.POState == (sbyte)OrderState.New || x.POState == (sbyte)OrderState.Active))
|
|
.OrderBy(x => x.POName).Asc
|
|
.List<OrderInfo>();
|
|
|
|
for (int i = list.Count - 1; i >= 0; i--)
|
|
{
|
|
long orderNr;
|
|
if (!long.TryParse(list[i].POName, out orderNr) || orderNr - 1 < predefinedOrders.Length)
|
|
{
|
|
list.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
else
|
|
{
|
|
return session.QueryOver<OrderInfo>()
|
|
.OrderBy(x => x.POName).Asc
|
|
.List<OrderInfo>();
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
log.ErrorFormat("Failed to load processes from the tracing DB: {0}", exc.Message);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates target and completed pieces count and returns
|
|
/// true when target pieces count was reached.
|
|
/// </summary>
|
|
/// <returns>true when target pieces count reached</returns>
|
|
public bool UpdatePiecesCount()
|
|
{
|
|
if (CurrentOrder == null || predefinedOrders.Contains(orderComboBox.Text))
|
|
{
|
|
targetGroupBox.Visible = false;
|
|
targetLabel.Text = "0";
|
|
|
|
completedGroupBox.Visible = false;
|
|
completedLabel.Text = "0";
|
|
completedGroupBox.BackColor = SystemColors.Control;
|
|
completedGroupBox.ForeColor = SystemColors.ControlText;
|
|
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
targetGroupBox.Visible = true;
|
|
targetLabel.Text = CurrentOrder.PiecesCount.ToString();
|
|
|
|
if (CurrentWorkflow != null && CurrentWorkstep != null)
|
|
{
|
|
try
|
|
{
|
|
var pieces = dbSession.QueryOver<ReferenceRecord>()
|
|
.Where(x => x.POName == CurrentOrder.POName)
|
|
.And(x => x.Workflow == CurrentWorkflow.Name)
|
|
.List<ReferenceRecord>();
|
|
|
|
completedGroupBox.Visible = true;
|
|
completedLabel.Text = pieces.Count.ToString();
|
|
|
|
bool targetReached = pieces.Count >= CurrentOrder.PiecesCount;
|
|
completedGroupBox.BackColor = targetReached ? Color.Green : SystemColors.Control;
|
|
completedGroupBox.ForeColor = targetReached ? Color.White : SystemColors.ControlText;
|
|
return targetReached;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
completedGroupBox.Visible = true;
|
|
completedLabel.Text = Strings.unknown;
|
|
completedGroupBox.BackColor = SystemColors.Control;
|
|
completedGroupBox.ForeColor = SystemColors.ControlText;
|
|
log.ErrorFormat("Unable to read ReferenceRecords: o={0} w={1} s={2}: {3}",
|
|
CurrentOrder.POName, CurrentWorkflow.Name, CurrentWorkstep.Name, exc.Message);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
completedGroupBox.Visible = false;
|
|
completedLabel.Text = "0";
|
|
completedGroupBox.BackColor = SystemColors.Control;
|
|
completedGroupBox.ForeColor = SystemColors.ControlText;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void UpdateOrderCombo(IList<OrderInfo> orders, string preferredOrderName)
|
|
{
|
|
bool anyChange = (orders == null) || (predefinedOrders.Length + orders.Count != orderComboBox.Items.Count);
|
|
if (!anyChange)
|
|
{
|
|
for (int i = 0; i < orders.Count; i++)
|
|
{
|
|
if (orderComboBox.Items[i].ToString() != orders[i].POName)
|
|
{
|
|
anyChange = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!anyChange) return;
|
|
|
|
int selectedIndex = -1;
|
|
|
|
orderComboBox.Items.Clear();
|
|
if (orders != null)
|
|
{
|
|
for (int i = 0; i < predefinedOrders.Length; i++)
|
|
{
|
|
orderComboBox.Items.Add(predefinedOrders[i]);
|
|
if (predefinedOrders[i] == preferredOrderName)
|
|
{
|
|
selectedIndex = i;
|
|
CurrentOrder = AllOrders.FirstOrDefault<OrderInfo>(x => x.POName == (i + 1).ToString("D7"));
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < orders.Count; i++)
|
|
{
|
|
orderComboBox.Items.Add(orders[i]);
|
|
if (orders[i].POName == preferredOrderName)
|
|
{
|
|
selectedIndex = predefinedOrders.Length + i;
|
|
CurrentOrder = orders[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
orderComboBox.SelectedIndex = selectedIndex;
|
|
UpdatePiecesCount();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Redraw processes in process combo box. Try to keep Program.LocalSettings.LastProcess selected.
|
|
/// In case of a change in ReleaseActive processes in the DB it may not be possible to keep this selection.
|
|
/// In such case function returns null.
|
|
/// When process selection changes, 'processComboBox_SelectedIndexChanged' is invoked.
|
|
/// </summary>
|
|
/// <returns>true = list of processes changed</returns>
|
|
bool UpdateWorkflowCombo(IList<Process> workflows, string preferredWorkflowName)
|
|
{
|
|
if (workflows == null || workflows.Count == 0)
|
|
{
|
|
supressUINotifications = true;
|
|
workflowComboBox.Items.Clear();
|
|
workflowComboBox.Text = string.Empty;
|
|
supressUINotifications = false;
|
|
|
|
bool wflowChgnd = (CurrentWorkflow != null);
|
|
CurrentWorkflow = null;
|
|
return wflowChgnd;
|
|
}
|
|
|
|
Process preferredWorkflow = workflows.FirstOrDefault<Process>(x => x.Name == preferredWorkflowName);
|
|
|
|
supressUINotifications = true;
|
|
workflowComboBox.Items.Clear();
|
|
for (int i = 0; i < workflows.Count; i++)
|
|
{
|
|
workflowComboBox.Items.Add(workflows[i].Name);
|
|
}
|
|
workflowComboBox.Text = (preferredWorkflow != null) ? preferredWorkflowName : string.Empty;
|
|
supressUINotifications = false;
|
|
|
|
bool workflowChanged = CurrentWorkflow != preferredWorkflow;
|
|
CurrentWorkflow = preferredWorkflow;
|
|
return workflowChanged;
|
|
}
|
|
|
|
|
|
private void workflowComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
if (supressUINotifications) return;
|
|
|
|
CurrentWorkflow = workflows.FirstOrDefault<Process>(x => x.Name == workflowComboBox.Text);
|
|
|
|
if (UpdateWorkstepCombo(CurrentWorkflow, workstepComboBox.Text))
|
|
{
|
|
UpdateItems();
|
|
ClearBatchNumbers();
|
|
Program.LocalSettings.LastWorkflow = CurrentWorkflow.Name;
|
|
Program.LocalSettings.LastWorkstep = CurrentWorkstep.Name;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Updates workstep selection combo items and text. Clear it only if process == null.
|
|
/// If there is a valid 'oriWorkstepName', the combo box text is set and the selected workstep is returned.
|
|
/// Otherwise this function returns null.
|
|
/// </summary>
|
|
/// <param name="workflow">Process with worksteps to be used</param>
|
|
/// <param name="preferredWorkstepName">Originally selected workstep name</param>
|
|
/// <returns>New selected workstep or null</returns>
|
|
private bool UpdateWorkstepCombo(Process workflow, string preferredWorkstepName)
|
|
{
|
|
if (workflow == null || workflow.Worksteps == null || workflow.Worksteps.Count == 0)
|
|
{
|
|
supressUINotifications = true;
|
|
workstepComboBox.Items.Clear();
|
|
workstepComboBox.Text = string.Empty;
|
|
supressUINotifications = false;
|
|
|
|
bool wstepChgnd = (CurrentWorkstep != null);
|
|
CurrentWorkstep = null;
|
|
return wstepChgnd;
|
|
}
|
|
|
|
/// Todo: Select closes workstep
|
|
Workstep prefferedWorkstep = workflow.Worksteps.FirstOrDefault(x => x.Name == preferredWorkstepName);
|
|
|
|
supressUINotifications = true;
|
|
workstepComboBox.Items.Clear();
|
|
for (int i = 0; i < workflow.Worksteps.Count; i++)
|
|
{
|
|
workstepComboBox.Items.Add(workflow.Worksteps[i].Name);
|
|
}
|
|
workstepComboBox.Text = (prefferedWorkstep != null) ? preferredWorkstepName : string.Empty;
|
|
supressUINotifications = false;
|
|
|
|
bool workstepChanged = CurrentWorkstep != prefferedWorkstep;
|
|
CurrentWorkstep = prefferedWorkstep;
|
|
return workstepChanged;
|
|
}
|
|
|
|
|
|
private void workstepComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
if (supressUINotifications) return;
|
|
|
|
var oriWorkstep = CurrentWorkstep;
|
|
CurrentWorkstep = CurrentWorkflow == null
|
|
? null
|
|
: CurrentWorkflow.Worksteps.FirstOrDefault<Workstep>(x => x.Name == workstepComboBox.Text);
|
|
|
|
if (CurrentWorkstep != oriWorkstep)
|
|
{
|
|
UpdateItems();
|
|
ClearBatchNumbers();
|
|
Program.LocalSettings.LastWorkstep = CurrentWorkstep.Name;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Updates screen items (polozky) and currentProcess, currentWorkstep variables.
|
|
/// If either process or workstep is null, the screen is icleared.
|
|
/// </summary>
|
|
/// <param name="process">Process to be used (drawn)</param>
|
|
/// <param name="workstep">Workstep to be used (drawn)</param>
|
|
/// <returns>true = process or workstep changed, false = no change</returns>
|
|
void UpdateItems()
|
|
{
|
|
if (recordProcessing != null) recordProcessing.StopProcessing();
|
|
|
|
workstepsOfTheCurrentWorkflow = CurrentWorkflow != null ? CurrentWorkflow.Worksteps : new List<Workstep>();
|
|
verifiedWorkstep = null; /// Disable any verification
|
|
|
|
RedrawItems();
|
|
|
|
if (CurrentOrder != null)
|
|
{
|
|
completedGroupBox.Visible = targetGroupBox.Visible = true;
|
|
UpdatePiecesCount();
|
|
}
|
|
else
|
|
{
|
|
completedGroupBox.Visible = targetGroupBox.Visible = false;
|
|
}
|
|
|
|
if (CurrentWorkflow != null)
|
|
{
|
|
LoadCodesFromDictionary(CurrentWorkflow.Name, palety);
|
|
}
|
|
|
|
ScanVerificationInfo svi = TracingDB.AnalyzeProcess(dbSession, CurrentWorkflow, CurrentWorkstep);
|
|
if (svi != null)
|
|
{
|
|
verifiedWorkstep = svi.Workstep;
|
|
verifiedPart = svi.Part;
|
|
verifyReferencePart = svi.VerifyReferencePart;
|
|
}
|
|
UpdateTitle(); /// Show acrive verification
|
|
wplaceRegistration.UpdateRegistration(dbSession,
|
|
Program.LocalSettings.WorkplaceId,
|
|
Common.CurrentUser.UserName(),
|
|
"1.2.3.4",
|
|
(CurrentWorkflow != null) ? CurrentWorkflow.Name : string.Empty,
|
|
(CurrentWorkstep != null) ? CurrentWorkstep.Name : string.Empty,
|
|
DateTime.Now + new TimeSpan(8, 0, 0));
|
|
|
|
if (recordProcessing != null) recordProcessing.StartProcessing();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Update main window title after AnalyzeProcesses()
|
|
/// </summary>
|
|
void UpdateTitle()
|
|
{
|
|
string title = string.Format("{0} ver. {1} ({2})", Strings.Workplace, Program.Version, Program.LocalSettings.WorkplaceId);
|
|
if (verifiedWorkstep != null && verifiedPart != null)
|
|
{
|
|
title += string.Format(Strings.previous_workflow_step_0_verified_component_1, verifiedWorkstep.Name, verifiedPart.Name);
|
|
}
|
|
Text = title;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Redraw items (polozky) of the currentProcess and currentWorkstep
|
|
/// or clear them if there is no current process or workstep.
|
|
/// </summary>
|
|
void RedrawItems()
|
|
{
|
|
///
|
|
/// Remove existing items (polozky)
|
|
///
|
|
foreach (var k in komponenty) if (k is IDevice) (k as IDevice).StopDevice();
|
|
foreach (var p in palety) if (p is IDevice) (p as IDevice).StopDevice();
|
|
komponenty.Clear();
|
|
palety.Clear();
|
|
flowLayoutPanel1.Controls.Clear();
|
|
flowLayoutPanel2.Controls.Clear();
|
|
|
|
ICheckItem polozka;
|
|
|
|
if (CurrentWorkstep != null)
|
|
{
|
|
/// Reference part
|
|
if (CurrentWorkstep.ReferencePart != null)
|
|
{
|
|
if (CurrentWorkstep.ReferencePart.CodeForm == (sbyte)CodeForm.Barcode ||
|
|
CurrentWorkstep.ReferencePart.CodeForm == (sbyte)CodeForm.QRCode)
|
|
{
|
|
polozka = new CheckItems.Barcode(this, CurrentWorkstep.ReferencePart);
|
|
polozka.IxPolozky = 1;
|
|
komponenty.Add(polozka);
|
|
flowLayoutPanel1.Controls.Add(polozka as UserControl);
|
|
|
|
OptionalySetBlackList(polozka);
|
|
}
|
|
else if (CurrentWorkstep.ReferencePart.CodeForm == (sbyte)CodeForm.SNGenerator)
|
|
{
|
|
polozka = new CheckItems.SNGeneratorPrinter(this, CurrentWorkstep.ReferencePart);
|
|
polozka.IxPolozky = 1;
|
|
komponenty.Add(polozka);
|
|
flowLayoutPanel1.Controls.Add(polozka as UserControl);
|
|
}
|
|
}
|
|
/// All other parts
|
|
foreach (var p in CurrentWorkstep.Parts)
|
|
{
|
|
if (komponenty.Count == 1 && p.CodeForm == (sbyte)CodeForm.SerialNr)
|
|
{
|
|
/// Complete serial number 'part' that is handled by PolozkaDouble => do not create any new control
|
|
continue;
|
|
}
|
|
|
|
switch ((CodeForm)p.CodeForm)
|
|
{
|
|
case CodeForm.SNGenerator:
|
|
polozka = new CheckItems.SNGeneratorPrinter(this, p);
|
|
break;
|
|
|
|
case CodeForm.Keyboard:
|
|
polozka = new CheckItems.Keyboard(this, p);
|
|
break;
|
|
|
|
case CodeForm.Scale:
|
|
RunWeightLimitsWizard(); /// Run wizard to determine weight limits before creating a scale CheckItem
|
|
|
|
CheckItems.Scale scale = new CheckItems.Scale(this, p);
|
|
try { scale.Initialize(); }
|
|
catch (Exception) { scale.BackColor = System.Drawing.Color.Red; }
|
|
scale.MinWeight = Program.LocalSettings.MinWeight / 1000;
|
|
scale.MaxWeight = Program.LocalSettings.MaxWeight / 1000;
|
|
polozka = scale;
|
|
break;
|
|
|
|
case CodeForm.DataStream:
|
|
CheckItems.S640Stream datastream = new CheckItems.S640Stream(this, p);
|
|
try { datastream.Initialize(); }
|
|
catch (Exception) { datastream.BackColor = System.Drawing.Color.Red; }
|
|
polozka = datastream;
|
|
break;
|
|
|
|
case CodeForm.Barcode:
|
|
case CodeForm.QRCode:
|
|
default:
|
|
polozka = new CheckItems.Barcode(this, p);
|
|
break;
|
|
}
|
|
|
|
if (p.CodeLocation == CodeLocation.OnPart)
|
|
{
|
|
polozka.IxPolozky = komponenty.Count + 1;
|
|
komponenty.Add(polozka);
|
|
flowLayoutPanel1.Controls.Add(polozka as UserControl);
|
|
}
|
|
else if (p.CodeLocation == CodeLocation.OnPallet)
|
|
{
|
|
polozka.IxPolozky = palety.Count + 100;
|
|
palety.Add(polozka);
|
|
flowLayoutPanel2.Controls.Add(polozka as UserControl);
|
|
}
|
|
|
|
OptionalySetBlackList(polozka);
|
|
}
|
|
|
|
InitializeSNGeneratorPrinter();
|
|
}
|
|
}
|
|
|
|
|
|
void RunWeightLimitsWizard()
|
|
{
|
|
while (true)
|
|
{
|
|
var dr = MessageBox.Show(Strings.Do_you_want_to_use_the_last + Environment.NewLine
|
|
+ string.Format(Strings.weight_limits_0g_1g_Q, Program.LocalSettings.MinWeight, Program.LocalSettings.MaxWeight)
|
|
+ Environment.NewLine + Program.LocalSettings.WeightOptionsWay,
|
|
string.Empty,
|
|
MessageBoxButtons.YesNo,
|
|
MessageBoxIcon.Question);
|
|
|
|
if (dr == DialogResult.Yes) return; /// Use the last weight limits stored in Program.LocalSettings
|
|
|
|
/// Ask how the new weight limits should be determined
|
|
var dlg1 = new Forms.WeightLimitsWayDlg();
|
|
dlg1.ShowDialog();
|
|
switch (dlg1.Way)
|
|
{
|
|
case Forms.Way.Manually:
|
|
/// Enter weight limits manually
|
|
var dlg2 = new Forms.WeightLimitsDlg(Program.LocalSettings.MinWeight, Program.LocalSettings.MaxWeight);
|
|
if (dlg2.ShowDialog() == DialogResult.OK)
|
|
{
|
|
Program.LocalSettings.MinWeight = dlg2.MinWeight;
|
|
Program.LocalSettings.MaxWeight = dlg2.MaxWeight;
|
|
Program.LocalSettings.WeightOptionsWay = dlg2.WeightOptionsWay;
|
|
Program.LocalSettings.Save();
|
|
}
|
|
return;
|
|
|
|
case Forms.Way.Wizard:
|
|
/// Use a wizard to determine the weight limits
|
|
var dlg3 = new Forms.WeightLimitsWizardDlg(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\WizardDirTree");
|
|
if (dlg3.ShowDialog() == DialogResult.OK)
|
|
{
|
|
Program.LocalSettings.MinWeight = dlg3.MinWeight;
|
|
Program.LocalSettings.MaxWeight = dlg3.MaxWeight;
|
|
Program.LocalSettings.WeightOptionsWay = dlg3.WeightOptionsWay;
|
|
Program.LocalSettings.Save();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
case Forms.Way.Measurement:
|
|
default:
|
|
MessageBox.Show(Strings.Not_implemented_yet);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ClearBatchNumbers()
|
|
{
|
|
if (loadedOnce)
|
|
{
|
|
foreach (var p in palety)
|
|
{
|
|
p.ClearCode();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Check local settings and optionally set the black list for polozka.
|
|
/// </summary>
|
|
/// <param name="polozka"></param>
|
|
void OptionalySetBlackList(ICheckItem polozka)
|
|
{
|
|
if (polozka.IxPolozky == Program.LocalSettings.BlackListIx1)
|
|
{
|
|
BlackList bl = BlackList.FromFile(Program.LocalSettings.BlackListFile1);
|
|
if (bl != null) polozka.BlackListedCodes = bl.Codes;
|
|
}
|
|
else if (polozka.IxPolozky == Program.LocalSettings.BlackListIx2)
|
|
{
|
|
BlackList bl = BlackList.FromFile(Program.LocalSettings.BlackListFile2);
|
|
if (bl != null) polozka.BlackListedCodes = bl.Codes;
|
|
}
|
|
else if (polozka.IxPolozky == Program.LocalSettings.BlackListIx3)
|
|
{
|
|
BlackList bl = BlackList.FromFile(Program.LocalSettings.BlackListFile3);
|
|
if (bl != null) polozka.BlackListedCodes = bl.Codes;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Reset idle time measurement
|
|
/// </summary>
|
|
void ResetIdleTime()
|
|
{
|
|
lastActivity = DateTime.Now;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get idle time in seconds
|
|
/// </summary>
|
|
/// <returns>Idle time [s]</returns>
|
|
double GetIdleTimeSec()
|
|
{
|
|
TimeSpan ts = DateTime.Now - lastActivity;
|
|
return (int)ts.TotalSeconds;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get time in seconds sinc the last login
|
|
/// </summary>
|
|
/// <returns>Login time [s]</returns>
|
|
double GetLoginTimeSec()
|
|
{
|
|
TimeSpan ts = DateTime.Now - lastLoginTime;
|
|
return (int)ts.TotalSeconds;
|
|
}
|
|
|
|
static TimeSpan oneDay = new TimeSpan(1, 0, 0, 0);
|
|
static int logoutDetectionCounter = 0;
|
|
///
|
|
void runDeviceTimer_Tick(object sender, EventArgs args)
|
|
{
|
|
try
|
|
{
|
|
/// Before
|
|
foreach (var k in komponenty) if (k is IDevice) (k as IDevice).RunDeviceBefore();
|
|
foreach (var p in palety) if (p is IDevice) (p as IDevice).RunDeviceBefore();
|
|
|
|
/// After
|
|
foreach (var k in komponenty) if (k is IDevice) (k as IDevice).RunDeviceAfter();
|
|
foreach (var p in palety) if (p is IDevice) (p as IDevice).RunDeviceAfter();
|
|
|
|
if (++logoutDetectionCounter >= 30)
|
|
{
|
|
logoutDetectionCounter = 0;
|
|
LogoutDetection();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
///
|
|
void LogoutDetection()
|
|
{
|
|
TimeSpan smallestTimeDiff = oneDay; /// Smallest time difference from logout times - initialized to one day
|
|
|
|
if (Program.LocalSettings.LogoutTime1.TimeOfDay != new TimeSpan(0))
|
|
{
|
|
/// Logout time 1 enabled
|
|
TimeSpan ts1 = DateTime.Now.TimeOfDay - Program.LocalSettings.LogoutTime1.TimeOfDay;
|
|
if (ts1 < new TimeSpan(0)) ts1 += oneDay;
|
|
if (ts1 < smallestTimeDiff) smallestTimeDiff = ts1;
|
|
}
|
|
|
|
if (Program.LocalSettings.LogoutTime2.TimeOfDay != new TimeSpan(0))
|
|
{
|
|
/// Logout time 2 enabled
|
|
TimeSpan ts2 = DateTime.Now.TimeOfDay - Program.LocalSettings.LogoutTime2.TimeOfDay;
|
|
if (ts2 < new TimeSpan(0)) ts2 += oneDay;
|
|
if (ts2 < smallestTimeDiff) smallestTimeDiff = ts2;
|
|
}
|
|
|
|
if (Program.LocalSettings.LogoutTime3.TimeOfDay != new TimeSpan(0))
|
|
{
|
|
/// Logout time 3 enabled
|
|
TimeSpan ts3 = DateTime.Now.TimeOfDay - Program.LocalSettings.LogoutTime3.TimeOfDay;
|
|
if (ts3 < new TimeSpan(0)) ts3 += oneDay;
|
|
if (ts3 < smallestTimeDiff) smallestTimeDiff = ts3;
|
|
}
|
|
|
|
int minTimeSec = (int)smallestTimeDiff.TotalSeconds;
|
|
|
|
if ((minTimeSec < 900) && !isLoggedOut && (GetIdleTimeSec() > 120) && (GetLoginTimeSec() > 2700))
|
|
{
|
|
logoutButton_Click(null, null);
|
|
}
|
|
}
|
|
|
|
|
|
public void OnBarcodeReceived(object sender, BarcodeReceivedEventArgs data)
|
|
{
|
|
ResetIdleTime();
|
|
|
|
if (BarcodeReceivedHandler == null) return;
|
|
|
|
try
|
|
{
|
|
BarcodeReceivedHandler(sender, data);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
string msg = exc.Message;
|
|
// log.Error("BarcodeReceivedHandler(...) failed", e);
|
|
}
|
|
}
|
|
public event EventHandler<BarcodeReceivedEventArgs> BarcodeReceivedHandler;
|
|
///
|
|
public void BarcodeReceived(object sender, BarcodeReceivedEventArgs data)
|
|
{
|
|
foreach (var k in komponenty) k.ResetFocus();
|
|
foreach (var p in palety) p.ResetFocus();
|
|
|
|
if (data.Error == PartError.BlacklistedPart)
|
|
{
|
|
///
|
|
/// This is a blacklisted component (s/n in on a blacklist)
|
|
///
|
|
SetErrorFlag(PartError.BlacklistedPart, Color.DarkOrange);
|
|
MessageBox.Show(string.Format("{0}{1}{2}",
|
|
Strings.This_part_is_on_a_black_list,
|
|
Environment.NewLine,
|
|
Strings.Put_the_part_aside),
|
|
Strings.Error, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
ResetErrorFlag();
|
|
return;
|
|
}
|
|
else if (data.Error == PartError.WrongPart)
|
|
{
|
|
///
|
|
/// This is a wrong part (s/n does not satisfy criteria)
|
|
///
|
|
SetErrorFlag(PartError.WrongPart, Color.Red);
|
|
MessageBox.Show(Strings.Wrong_part, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
ResetErrorFlag();
|
|
return;
|
|
}
|
|
else if (data.Error == PartError.ValueOutOfRange)
|
|
{
|
|
///
|
|
/// Measured value is out of range
|
|
///
|
|
SetErrorFlag(PartError.ValueOutOfRange, Color.Red);
|
|
MessageBox.Show(Strings.Value_out_of_range, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
ResetErrorFlag();
|
|
return;
|
|
}
|
|
else if (data.Error == PartError.UnspecifiedError)
|
|
{
|
|
///
|
|
/// Measured value is out of range
|
|
///
|
|
SetErrorFlag(PartError.UnspecifiedError, Color.Red);
|
|
MessageBox.Show(Strings.Unspecified_error, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
ResetErrorFlag();
|
|
return;
|
|
}
|
|
else if (data.CodeLocation == CodeLocation.OnPart)
|
|
{
|
|
///
|
|
/// This is a uniqueue part code ==> process it
|
|
///
|
|
if (data.IxPolozky > 0 && data.IxPolozky < komponenty.Count)
|
|
{
|
|
///
|
|
/// This is not the last part ==> set focus onto the next part to be scanned
|
|
///
|
|
komponenty[data.IxPolozky].SetFocus();
|
|
return;
|
|
}
|
|
|
|
///
|
|
/// This is the last part with uniqueue code (on the left side of the screen)
|
|
///
|
|
if(IsAnyFieldEmpty())
|
|
{
|
|
///
|
|
/// At least one of fields is empty ==> error
|
|
///
|
|
SetErrorFlag(PartError.FieldEmpty, Color.Yellow);
|
|
MessageBox.Show(Strings.Some_fileds_are_empty_Fill_them_in_please,
|
|
Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
ResetErrorFlag();
|
|
return;
|
|
}
|
|
|
|
if (errorFlag != PartError.None)
|
|
{
|
|
///
|
|
/// There is another error (see errorFlag)
|
|
///
|
|
SetErrorFlag(PartError.UnspecifiedError, Color.Red);
|
|
MessageBox.Show(Strings.Remove_errors_please,
|
|
Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
ResetErrorFlag();
|
|
return;
|
|
}
|
|
|
|
///
|
|
/// Everything is OK so far ==> verify previous records
|
|
///
|
|
try
|
|
{
|
|
ISession session = SessionFactory.OpenSession();
|
|
|
|
if (verifiedWorkstep != null && verifiedPart != null)
|
|
{
|
|
string verifiedCode = string.Empty;
|
|
for (int i = 0; i < komponenty.Count; i++)
|
|
{
|
|
if (komponenty[i].Part == verifiedPart)
|
|
{
|
|
verifiedCode = komponenty[i].ScannedCode;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int codeIx = 1;
|
|
|
|
///
|
|
/// Find reference records with s/n of the part to be verified
|
|
///
|
|
IQueryOver<ReferenceRecord, ReferenceRecord> query = dbSession.QueryOver<ReferenceRecord>();
|
|
switch (codeIx)
|
|
{
|
|
default:
|
|
case 1: query = query.Where(rr => (rr.Code1 == verifiedCode)); break;
|
|
case 2: query = query.Where(rr => (rr.Code2 == verifiedCode)); break;
|
|
case 3: query = query.Where(rr => (rr.Code3 == verifiedCode)); break;
|
|
case 4: query = query.Where(rr => (rr.Code4 == verifiedCode)); break;
|
|
}
|
|
var refRecords = query.OrderBy(rr => rr.Timestamp).Desc.List();
|
|
|
|
bool verificationPassed = false;
|
|
if (refRecords.Count > 0 && refRecords[0].StepRecords != null)
|
|
{
|
|
foreach (var r in refRecords[0].StepRecords)
|
|
{
|
|
if (r.Workstep == verifiedWorkstep.Name)
|
|
{
|
|
/// This is the last good record from a verified workstep
|
|
verificationPassed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!verificationPassed)
|
|
{
|
|
SetErrorFlag(PartError.PrviousRecordMissing, Color.Blue);
|
|
MessageBox.Show(Strings.Record_from_the_previous_workflow_step_is_missing,
|
|
Strings.Warning,
|
|
MessageBoxButtons.OK,
|
|
MessageBoxIcon.Exclamation);
|
|
ResetErrorFlag();
|
|
return;
|
|
}
|
|
}
|
|
|
|
#if false
|
|
saveAllCodesButton.Enabled = true;
|
|
saveAllCodesButton.Focus();
|
|
#else
|
|
SaveCodes(session);
|
|
#endif
|
|
session.Close();
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
log.ErrorFormat("SaveCodes, etc. failed: {0}", exc.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SaveCodes(ISession session)
|
|
{
|
|
ResetIdleTime();
|
|
|
|
if (Program.LocalSettings.Mode == Mode.Test || komponenty.Count == 0)
|
|
{
|
|
ColorFlash(this, new ColorFlashEventArgs(true, Color.Green, Program.LocalSettings.OkFlashDuration, Strings.Test));
|
|
return;
|
|
}
|
|
|
|
if (IsAnyFieldEmpty())
|
|
{
|
|
SetErrorFlag(PartError.FieldEmpty, Color.Yellow);
|
|
MessageBox.Show(Strings.Some_fileds_are_empty_Fill_them_in_please,
|
|
Strings.Warning,
|
|
MessageBoxButtons.OK,
|
|
MessageBoxIcon.Exclamation);
|
|
ResetErrorFlag();
|
|
return;
|
|
}
|
|
|
|
if (errorFlag != PartError.None)
|
|
{
|
|
MessageBox.Show(Strings.Remove_errors_please,
|
|
Strings.Warning,
|
|
MessageBoxButtons.OK,
|
|
MessageBoxIcon.Exclamation);
|
|
return;
|
|
}
|
|
|
|
///
|
|
/// Save records to MySQL
|
|
///
|
|
int result = 0; /// OK (default)
|
|
bool wasAlreadyTested = false;
|
|
bool componentsSaved = true;
|
|
bool successfullySaved = false;
|
|
ITransaction transaction = null;
|
|
try
|
|
{
|
|
transaction = session.BeginTransaction();
|
|
|
|
CheckItems.SNGeneratorPrinter snGenerator = (komponenty[0] as CheckItems.SNGeneratorPrinter); /// null when there is no S/N generator
|
|
|
|
///
|
|
/// Handle serial number generators
|
|
///
|
|
if (snGenerator != null && komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator)
|
|
{
|
|
if (CurrentOrder == null)
|
|
{
|
|
/// The 1st item is a S/N generator but no order is selected ==> Error
|
|
komponenty[0].ScannedCode = "ERROR";
|
|
throw new Exception("No order selected");
|
|
}
|
|
|
|
///
|
|
/// Negotiate and update the generated serial number
|
|
///
|
|
string generatedCode;
|
|
var orderInfoState = snGenerator.NegotiateSerialNr(session, CurrentOrder, CurrentWorkflow, CurrentWorkstep,
|
|
out generatedCode, true);
|
|
|
|
if (orderInfoState == OrderProgress.InProgress || orderInfoState == OrderProgress.Overproduction)
|
|
{
|
|
komponenty[0].ScannedCode = generatedCode;
|
|
}
|
|
else if (orderInfoState == OrderProgress.Completed)
|
|
{
|
|
komponenty[0].ScannedCode = "END";
|
|
throw new Exception("END");
|
|
}
|
|
else //if (orderInfoState == OrderProgress.Error)
|
|
{
|
|
/// An unexpected error
|
|
throw new Exception("No order selected");
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Select or create a reference record
|
|
///
|
|
var refRecords = session.QueryOver<ReferenceRecord>()
|
|
.Where(x => x.Code1 == komponenty[0].ScannedCode)
|
|
.List();
|
|
|
|
/// Handle or prevent reference record duplicity
|
|
if (refRecords.Count > 1) throw new Exception("Unexpected error: two identical codes in the database");
|
|
else if (snGenerator != null && refRecords.Count == 1) throw new Exception("A duplicit code was generated");
|
|
|
|
ReferenceRecord refRecord = (refRecords.Count == 1) ? refRecords[0]
|
|
: new ReferenceRecord(CurrentOrder.POName, CurrentWorkflow.Name, komponenty[0].Part.Name, komponenty[0].ScannedCode);
|
|
|
|
/// Handle case of a double check item - update refRecord.Code2
|
|
if (komponenty[0] is IDoubleCheckItem)
|
|
{
|
|
refRecord.Code2 = (komponenty[0] as IDoubleCheckItem).ScannedCode2;
|
|
}
|
|
|
|
/// Prepare new records
|
|
var records = new List<Record>();
|
|
var stepRecord = PrepareRecords(refRecord, result, records);
|
|
|
|
/// De-referene existing recors with the same part name, a more recent record exists now
|
|
foreach (var oriRecord in refRecord.Records)
|
|
{
|
|
var overridingRecord = records.FirstOrDefault(x => x.Name == oriRecord.Name);
|
|
if (overridingRecord != null)
|
|
{
|
|
oriRecord.ReferenceRecord = null;
|
|
session.SaveOrUpdate(oriRecord);
|
|
}
|
|
}
|
|
|
|
/// Update the reference record
|
|
refRecord.StepRecords.Add(stepRecord);
|
|
foreach (var rcrd in records) refRecord.Records.Add(rcrd);
|
|
if (stepRecord.Timestamp > refRecord.Timestamp) refRecord.Timestamp = stepRecord.Timestamp;
|
|
session.SaveOrUpdate(refRecord);
|
|
log.InfoFormat(" ReferenceRecord : {0}", refRecord);
|
|
|
|
/// Save new records
|
|
session.SaveOrUpdate(stepRecord);
|
|
log.InfoFormat(" StepRecord : {0}", stepRecord);
|
|
foreach (var rcrd in records)
|
|
{
|
|
session.SaveOrUpdate(rcrd);
|
|
log.InfoFormat(" Record : {0}", rcrd);
|
|
}
|
|
|
|
transaction.Commit();
|
|
successfullySaved = true;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
componentsSaved = false;
|
|
if (transaction != null) transaction.Rollback();
|
|
log.ErrorFormat("MySQL database transaction rolled back, data not comitted: {0}", exc.Message);
|
|
}
|
|
|
|
/// In case of 'SNGeneratorPrinter' print a label after saving records successfully
|
|
if (komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator && successfullySaved)
|
|
{
|
|
var matrix = new DataMatrix4Net.DataMatrix(komponenty[0].ScannedCode, DataMatrix4Net.SymbolSize.SquareAuto);
|
|
new Printers.DataMatrixAndTextPrintDoc(matrix.Matrix, komponenty[0].ScannedCode.Replace("4V", "\n")).Print();
|
|
}
|
|
|
|
/// Retrieve produced pieces count and compare with the target count
|
|
bool targetCountReached = UpdatePiecesCount();
|
|
|
|
|
|
if (wasAlreadyTested && !componentsSaved)
|
|
{
|
|
ColorFlash(this, new ColorFlashEventArgs(false, Color.Red, Program.LocalSettings.NokFlashDuration, Strings.PCB_was_tested_already, Strings.Components_were_not_saved_to_Oracle));
|
|
}
|
|
else if (wasAlreadyTested)
|
|
{
|
|
ColorFlash(this, new ColorFlashEventArgs(false, Color.Red, Program.LocalSettings.NokFlashDuration, Strings.PCB_was_tested_already));
|
|
}
|
|
else if (!componentsSaved)
|
|
{
|
|
ColorFlash(this, new ColorFlashEventArgs(false, Color.Red, Program.LocalSettings.NokFlashDuration, Strings.Components_were_not_saved_to_Oracle));
|
|
}
|
|
else if (targetCountReached)
|
|
{
|
|
ColorFlash(this, new ColorFlashEventArgs(false, Color.Yellow, Program.LocalSettings.NokFlashDuration, Strings.Target_count_reached));
|
|
}
|
|
else
|
|
{
|
|
ColorFlash(this, new ColorFlashEventArgs(true, Color.Green, Program.LocalSettings.OkFlashDuration));
|
|
}
|
|
|
|
|
|
UpdateAndSaveStoredCodesDictionary(CurrentWorkflow, palety);
|
|
|
|
///
|
|
/// Find out whether the process has been changed, prepare UI
|
|
///
|
|
orders = ReadOrders(dbSession);
|
|
UpdateOrderCombo(orders, orderComboBox.Text);
|
|
workflows = ReadReleasedActiveProcesses(dbSession);
|
|
if (UpdateWorkflowCombo(workflows, workflowComboBox.Text))
|
|
{
|
|
if (UpdateWorkstepCombo(CurrentWorkflow, workstepComboBox.Text))
|
|
{
|
|
UpdateItems();
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Clear all components/items, set focus to the first field
|
|
///
|
|
foreach (var k in komponenty)
|
|
{
|
|
k.ClearCode();
|
|
k.ResetFocus();
|
|
}
|
|
if (komponenty.Count >= 1)
|
|
{
|
|
if (komponenty.Count >= 2 && komponenty[0] is CheckItems.SNGeneratorPrinter
|
|
&& komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator)
|
|
{
|
|
komponenty[1].SetFocus();
|
|
}
|
|
else
|
|
{
|
|
komponenty[0].SetFocus();
|
|
}
|
|
}
|
|
|
|
if ((recordProcessing != null) && !wasAlreadyTested && componentsSaved)
|
|
{
|
|
/// Activate thirdparty program window
|
|
Utils.Activate(Program.LocalSettings.WindowClassNameToActivate);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepare records and a step record with scanned/generated/collected information
|
|
/// </summary>
|
|
/// <param name="refRecord">Reference record</param>
|
|
/// <param name="result">Result: 0=OK, otherwise a non-zero error code</param>
|
|
/// <param name="records">List of records to be updated (initially an empty list)</param>
|
|
/// <returns>Step record</returns>
|
|
StepRecord PrepareRecords(ReferenceRecord refRecord, int result, IList<Record> records)
|
|
{
|
|
var stepRecord = new StepRecord(refRecord, CurrentWorkstep.Name, workplaceTextBox.Text, workerTextBox.Text, result);
|
|
|
|
int firstNoRefCompIx = (CurrentWorkstep.ReferencePart == null) ? 0 : (komponenty[0] is IDoubleCheckItem) ? 2 : 1;
|
|
for (int i = firstNoRefCompIx; i < komponenty.Count; i++)
|
|
{
|
|
if (komponenty[i] is CheckItems.S640Stream)
|
|
{
|
|
/// eRegister number from data stream ... update refRecord.Code2
|
|
refRecord.Name2 = komponenty[i].Part.Name;
|
|
refRecord.Code2 = komponenty[i].ScannedCode;
|
|
}
|
|
else
|
|
{
|
|
records.Add(new Record(refRecord, stepRecord, komponenty[i].Part.Name, komponenty[i].ScannedCode, result));
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < palety.Count; i++)
|
|
{
|
|
records.Add(new Record(refRecord, stepRecord, palety[i].Part.Name, palety[i].ScannedCode, result));
|
|
}
|
|
|
|
return stepRecord;
|
|
}
|
|
|
|
void SetErrorFlag(PartError errorCode, Color backColor)
|
|
{
|
|
if (errorFlag == PartError.None)
|
|
{
|
|
Console.Beep(ErrorBeepFrequency, ErrorBeepDuration);
|
|
errorFlag = errorCode;
|
|
BackColor = backColor;
|
|
saveAllCodesButton.Enabled = false;
|
|
failedCheckBox.Checked = true;
|
|
}
|
|
}
|
|
|
|
void ResetErrorFlag()
|
|
{
|
|
if (errorFlag != PartError.None)
|
|
{
|
|
errorFlag = PartError.None;
|
|
BackColor = SystemColors.Control;
|
|
saveAllCodesButton.Enabled = true;
|
|
failedCheckBox.Checked = false;
|
|
foreach (var k in komponenty) k.ClearCode(); ;
|
|
if (komponenty.Count > 0) komponenty[0].SetFocus();
|
|
}
|
|
}
|
|
|
|
private void resetErrorStateButton_Click(object sender, EventArgs e)
|
|
{
|
|
ResetErrorFlag();
|
|
}
|
|
|
|
public void OnFocusPressed(object sender, FocusPressedEventArgs data)
|
|
{
|
|
ResetIdleTime();
|
|
|
|
if (FocusPressedHandler == null) return;
|
|
|
|
try
|
|
{
|
|
FocusPressedHandler(sender, data);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// log.Error("FocusPressedHandler(...) failed", e);
|
|
}
|
|
}
|
|
public event EventHandler<FocusPressedEventArgs> FocusPressedHandler;
|
|
///
|
|
public void FocusPressed(object sender, FocusPressedEventArgs data)
|
|
{
|
|
foreach (var k in komponenty) k.ResetFocus();
|
|
foreach (var p in palety) p.ResetFocus();
|
|
|
|
if ((data.IxPolozky >= 1) && (data.IxPolozky <= komponenty.Count))
|
|
{
|
|
komponenty[data.IxPolozky - 1].SetFocus();
|
|
}
|
|
else if ((data.IxPolozky >= 100) && (data.IxPolozky - 100 < palety.Count))
|
|
{
|
|
palety[data.IxPolozky - 100].SetFocus();
|
|
}
|
|
}
|
|
|
|
private void clearButton_Click(object sender, EventArgs e)
|
|
{
|
|
ResetIdleTime();
|
|
|
|
foreach (var k in komponenty)
|
|
{
|
|
k.ClearCode();
|
|
k.ResetFocus();
|
|
}
|
|
|
|
foreach (var p in palety)
|
|
{
|
|
p.ResetFocus();
|
|
}
|
|
|
|
InitializeSNGeneratorPrinter();
|
|
}
|
|
|
|
void InitializeSNGeneratorPrinter()
|
|
{
|
|
if (komponenty.Count > 0 &&
|
|
komponenty[0] is CheckItems.SNGeneratorPrinter &&
|
|
komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator &&
|
|
CurrentOrder != null)
|
|
{
|
|
try
|
|
{
|
|
var session = SessionFactory.OpenSession();
|
|
string generatedCode;
|
|
var rslt = (komponenty[0] as CheckItems.SNGeneratorPrinter)
|
|
.NegotiateSerialNr(session, CurrentOrder, CurrentWorkflow, CurrentWorkstep, out generatedCode, false);
|
|
komponenty[0].ScannedCode = (rslt == OrderProgress.Error) ? "ERROR"
|
|
: (rslt == OrderProgress.Completed) ? "END"
|
|
: generatedCode;
|
|
session.Close();
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
log.ErrorFormat("Failed to negotiate s/n in InitializeSNGeneratorPrinter(): {0}", exc.Message);
|
|
}
|
|
}
|
|
|
|
if (komponenty.Count > 1 &&
|
|
komponenty[0] is CheckItems.SNGeneratorPrinter &&
|
|
komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator)
|
|
{
|
|
komponenty[1].SetFocus();
|
|
}
|
|
else if (komponenty.Count > 0)
|
|
{
|
|
komponenty[0].SetFocus();
|
|
}
|
|
}
|
|
|
|
private void saveAllCodesButton_Click(object sender, EventArgs e)
|
|
{
|
|
if (isSNPrinting) saveAllCodesButton.Enabled = false;
|
|
|
|
try
|
|
{
|
|
var session = SessionFactory.OpenSession();
|
|
SaveCodes(session);
|
|
session.Close();
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
string msg = string.Format("Failed to save codes: {0}", exc.Message);
|
|
log.Error(msg);
|
|
MessageBox.Show(msg);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the dictionary of scanned codes of palettes and save it.
|
|
/// Dictionary contains pairs (process.Name, '~'-separated strings of scanned codes).
|
|
/// Update codes of parts with CodeType == CodeType.Silicon and shared between workflows as well.
|
|
/// </summary>
|
|
/// <param name="processName">Current workflow name</param>
|
|
/// <param name="palety">A list of palettes</param>
|
|
/// <returns>true = LocalSettings updated and saved</returns>
|
|
bool UpdateAndSaveStoredCodesDictionary(Process process, IList<ICheckItem> palety)
|
|
{
|
|
if (process == null || string.IsNullOrEmpty(process.Name) || palety == null || palety.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
StringBuilder sbSilicon = new StringBuilder();
|
|
StringBuilder sb = new StringBuilder();
|
|
bool firstSilicon = true;
|
|
bool first = true;
|
|
foreach (var p in palety)
|
|
{
|
|
if (p.Part.CodeType == (sbyte)CodeType.Silicon)
|
|
{
|
|
if (!firstSilicon) sbSilicon.Append("~");
|
|
firstSilicon = false;
|
|
sbSilicon.Append(p.ScannedCode);
|
|
}
|
|
else
|
|
{
|
|
if (!first) sb.Append("~");
|
|
first = false;
|
|
sb.Append(p.ScannedCode);
|
|
}
|
|
}
|
|
string value = sb.ToString();
|
|
|
|
string key = process.Name;
|
|
string storedValue;
|
|
if (!Program.LocalSettings.LastData.TryGetValue(key, out storedValue))
|
|
{
|
|
Program.LocalSettings.LastData.Add(key, value);
|
|
Program.LocalSettings.LastSiliconData = sbSilicon.ToString();
|
|
Program.LocalSettings.Save();
|
|
return true;
|
|
}
|
|
else if (storedValue != value)
|
|
{
|
|
Program.LocalSettings.LastData[key] = value;
|
|
Program.LocalSettings.LastSiliconData = sbSilicon.ToString();
|
|
Program.LocalSettings.Save();
|
|
return true;
|
|
}
|
|
else if (sbSilicon.ToString() != Program.LocalSettings.LastSiliconData)
|
|
{
|
|
Program.LocalSettings.LastSiliconData = sbSilicon.ToString();
|
|
Program.LocalSettings.Save();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load codes of palettes from the dictionary.
|
|
/// Dictionary contains pairs (process.Name, '~'-separated strings of scanned codes).
|
|
/// </summary>
|
|
/// <param name="processName">Current process name</param>
|
|
/// <param name="palety">A list of palettes</param>
|
|
void LoadCodesFromDictionary(string processName, IList<ICheckItem> palety)
|
|
{
|
|
if (string.IsNullOrEmpty(processName) || palety == null) return;
|
|
|
|
string[] loadedCodes = new string[0];
|
|
string value;
|
|
if (Program.LocalSettings.LastData.TryGetValue(processName, out value))
|
|
{
|
|
loadedCodes = value.Split(new char[] { '~' });
|
|
}
|
|
|
|
|
|
string[] loadedSiliconCodes = new string[0];
|
|
try
|
|
{
|
|
#if SILICON
|
|
SiliconBatchNumbers.SiliconBatchNumbers sbn;
|
|
if (null != (sbn = SiliconBatchNumbers.SiliconBatchNumbers.Load("N:\\iPERL vyroba Stara Tura\\software\\sarze silikonu\\Cfg\\silicon.xml")) ||
|
|
null != (sbn = SiliconBatchNumbers.SiliconBatchNumbers.Load("N:\\iPERL vyroba Stara Tura\\software\\sarze silikonu\\Cfg\\silicon.backup.xml")))
|
|
{
|
|
/// silicon batch numbers loaded from silicon.backup.xml
|
|
loadedSiliconCodes = sbn.GetSiliconBatchNumbers(Program.LocalSettings.WorkplaceId);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
loadedSiliconCodes = new string[0];
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
loadedSiliconCodes = new string[0];
|
|
}
|
|
|
|
|
|
int ix = 0;
|
|
int ixSilicon = 0;
|
|
for (int i = 0; i < palety.Count; i++)
|
|
{
|
|
if ((palety[i].Part.CodeType == (sbyte)CodeType.Silicon) && (ixSilicon < loadedSiliconCodes.Length))
|
|
{
|
|
palety[i].ScannedCode = loadedSiliconCodes[ixSilicon++];
|
|
}
|
|
if (!string.IsNullOrEmpty(palety[i].Part.DefaultCode))
|
|
{
|
|
palety[i].ScannedCode = palety[i].Part.DefaultCode;
|
|
ix++;
|
|
}
|
|
else if (ix < loadedCodes.Length)
|
|
{
|
|
palety[i].ScannedCode = loadedCodes[ix++];
|
|
}
|
|
else
|
|
{
|
|
palety[i].ClearCode();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns true if any field is empty
|
|
/// </summary>
|
|
private bool IsAnyFieldEmpty()
|
|
{
|
|
foreach (var k in komponenty)
|
|
{
|
|
if (k.ScannedCode == string.Empty) return true;
|
|
}
|
|
|
|
foreach (var p in palety)
|
|
{
|
|
if (p.ScannedCode == string.Empty) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear fields in the left pane and set focus to the beginning
|
|
/// </summary>
|
|
private void ClearFieldsResetFocus()
|
|
{
|
|
foreach (var k in komponenty)
|
|
{
|
|
k.ClearCode();
|
|
k.ResetFocus();
|
|
}
|
|
foreach (var p in palety)
|
|
{
|
|
p.ResetFocus();
|
|
}
|
|
komponenty[0].SetFocus();
|
|
}
|
|
|
|
|
|
private void WorkplaceDlg_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
bool anyChange = false;
|
|
UpdateAndSaveStoredCodesDictionary(CurrentWorkflow, palety);
|
|
if ((CurrentWorkflow != null) && (Program.LocalSettings.LastWorkflow != CurrentWorkflow.Name))
|
|
{
|
|
Program.LocalSettings.LastWorkflow = CurrentWorkflow.Name;
|
|
anyChange = true;
|
|
}
|
|
if ((CurrentWorkstep != null) && (Program.LocalSettings.LastWorkstep != CurrentWorkstep.Name))
|
|
{
|
|
Program.LocalSettings.LastWorkstep = CurrentWorkstep.Name;
|
|
anyChange = true;
|
|
}
|
|
if (anyChange) Program.LocalSettings.Save();
|
|
|
|
if (recordProcessing != null) recordProcessing.StopProcessing();
|
|
|
|
wplaceRegistration.UnregisterWorkplace(dbSession);
|
|
}
|
|
|
|
|
|
private void configureButton_Click(object sender, EventArgs e)
|
|
{
|
|
LoginAndConfigure();
|
|
}
|
|
|
|
|
|
private void LoginAndConfigure()
|
|
{
|
|
ResetIdleTime();
|
|
|
|
if (new LoginDlg(Program.SettingsAccessLevel, null).ShowDialog() == DialogResult.OK)
|
|
{
|
|
string oriWorkplace = Program.LocalSettings.WorkplaceId;
|
|
if (Configure() == DialogResult.OK)
|
|
{
|
|
orders = ReadOrders(dbSession);
|
|
UpdateOrderCombo(orders, orderComboBox.Text);
|
|
|
|
workflows = ReadReleasedActiveProcesses(dbSession);
|
|
UpdateWorkflowCombo(workflows, workflowComboBox.Text);
|
|
|
|
wplaceRegistration.UpdateRegistration(dbSession,
|
|
Program.LocalSettings.WorkplaceId,
|
|
Common.CurrentUser.UserName(),
|
|
"1.2.3.4",
|
|
(CurrentWorkflow != null) ? CurrentWorkflow.Name : string.Empty,
|
|
(CurrentWorkstep != null) ? CurrentWorkstep.Name : string.Empty,
|
|
DateTime.Now + new TimeSpan(8, 0, 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Show settings dialog, return DialogResult.OK when any option changed.
|
|
/// </summary>
|
|
/// <returns>true on any change in Program.LoclSettings</returns>
|
|
private DialogResult Configure()
|
|
{
|
|
var dlg = new Forms.SettingsDlg(Program.LocalSettings);
|
|
|
|
if (dlg.ShowDialog() == DialogResult.OK)
|
|
{
|
|
Program.LocalSettings.Save();
|
|
return DialogResult.OK;
|
|
}
|
|
else
|
|
{
|
|
return DialogResult.Cancel;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Called from the state machine when an operation forces a modeless dialog close.
|
|
/// </summary>
|
|
public static void ColorFlash(object sender, ColorFlashEventArgs args)
|
|
{
|
|
if (ColorFlashHandler == null) return;
|
|
try { ColorFlashHandler(sender, args); }
|
|
catch (Exception) { }
|
|
}
|
|
public static event EventHandler<ColorFlashEventArgs> ColorFlashHandler;
|
|
|
|
|
|
private static System.Windows.Forms.Timer colorFlashDurationTimer;
|
|
|
|
void OnColorFlash(object sender, ColorFlashEventArgs args)
|
|
{
|
|
// start timer here
|
|
if (colorFlashDurationTimer == null)
|
|
{
|
|
colorFlashDurationTimer = new System.Windows.Forms.Timer();
|
|
colorFlashDurationTimer.Tick += (s, e) => { ColorFlashAction(); };
|
|
}
|
|
|
|
BackColor = args.Color;
|
|
|
|
if (args.Message1 != null) { label1.Text = args.Message1; }
|
|
if (args.Message2 != null) { label2.Text = args.Message2; }
|
|
|
|
colorFlashDurationTimer.Interval = args.Interval;
|
|
colorFlashDurationTimer.Start();
|
|
|
|
if (args.OK)
|
|
{
|
|
Console.Beep();
|
|
}
|
|
else
|
|
{
|
|
Console.Beep(ErrorBeepFrequency, ErrorBeepDuration);
|
|
}
|
|
}
|
|
|
|
// Specify what you want to happen when the Elapsed event is
|
|
// raised.
|
|
private void ColorFlashAction()
|
|
{
|
|
BackColor = SystemColors.Control;
|
|
label1.Text = string.Empty;
|
|
label2.Text = string.Empty;
|
|
|
|
colorFlashDurationTimer.Stop();
|
|
colorFlashDurationTimer.Enabled = false;
|
|
|
|
if (isSNPrinting)
|
|
{
|
|
saveAllCodesButton.Enabled = true;
|
|
saveAllCodesButton.Focus();
|
|
}
|
|
}
|
|
|
|
|
|
private void logoutButton_Click(object sender, EventArgs e)
|
|
{
|
|
workerTextBox.Text = string.Empty;
|
|
isLoggedOut = true;
|
|
|
|
///
|
|
/// User login
|
|
///
|
|
while (true)
|
|
{
|
|
DialogResult dr;
|
|
switch (Program.LocalSettings.LocalWorkplacesCount)
|
|
{
|
|
default:
|
|
case 1:
|
|
dr = new LoginDlg().ShowDialog();
|
|
break;
|
|
case 2:
|
|
dr = new DoubleLoginDlg(Program.LocalSettings.LocalWorkplace1,
|
|
Program.LocalSettings.LocalWorkplace2, this).ShowDialog();
|
|
break;
|
|
case 3:
|
|
dr = new TripleLoginDlg(Program.LocalSettings.LocalWorkplace1,
|
|
Program.LocalSettings.LocalWorkplace2,
|
|
Program.LocalSettings.LocalWorkplace3, this).ShowDialog();
|
|
break;
|
|
}
|
|
|
|
if (dr == DialogResult.OK) break;
|
|
}
|
|
|
|
workerTextBox.Text = Common.CurrentUser.UserName();
|
|
lastLoginTime = DateTime.Now;
|
|
isLoggedOut = false;
|
|
ClearBatchNumbers();
|
|
wplaceRegistration.UpdateRegistration(dbSession,
|
|
Program.LocalSettings.WorkplaceId,
|
|
Common.CurrentUser.UserName(),
|
|
"1.2.3.4",
|
|
(CurrentWorkflow != null) ? CurrentWorkflow.Name : string.Empty,
|
|
(CurrentWorkstep != null) ? CurrentWorkstep.Name : string.Empty,
|
|
DateTime.Now + new TimeSpan(8, 0, 0));
|
|
}
|
|
|
|
private void refreshButton_Click(object sender, EventArgs e)
|
|
{
|
|
supressUINotifications = true;
|
|
orders = ReadOrders(dbSession);
|
|
UpdateOrderCombo(orders, orderComboBox.Text);
|
|
workflows = ReadReleasedActiveProcesses(dbSession);
|
|
if (UpdateWorkflowCombo(workflows, workflowComboBox.Text))
|
|
{
|
|
if (UpdateWorkstepCombo(CurrentWorkflow, workstepComboBox.Text))
|
|
{
|
|
UpdateItems();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void ManageCheckGroupBox(CheckBox chk, GroupBox grp)
|
|
{
|
|
/// Make sure the CheckBox isn't in the GroupBox. This will only happen the first time.
|
|
if (chk.Parent == grp)
|
|
{
|
|
grp.Parent.Controls.Add(chk); /// Reparent the CheckBox so it's not in the GroupBox.
|
|
chk.Location = new Point(chk.Left + grp.Left, chk.Top + grp.Top); /// Adjust the CheckBox's location.
|
|
chk.BringToFront(); /// Move the CheckBox to the top of the stacking order.
|
|
}
|
|
|
|
/// Enable or disable the GroupBox.
|
|
grp.Enabled = chk.Checked;
|
|
}
|
|
|
|
private void batchesCheckBox_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
ManageCheckGroupBox(batchesCheckBox, batchesGroupBox);
|
|
}
|
|
|
|
private void orderComboBox_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
if (e.KeyChar == '\r' && orderComboBox.Enabled)
|
|
{
|
|
/// Enter key was pressed, check whether orderComboBox contains a valid order number
|
|
orderComboBox_SelectedIndexChanged(sender, e);
|
|
}
|
|
}
|
|
|
|
private void orderComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
/// Check whether orderComboBox contains a valid order number
|
|
|
|
/// Check
|
|
for (int i = 0; i < predefinedOrders.Length; i++)
|
|
{
|
|
if (predefinedOrders[i] == orderComboBox.Text)
|
|
{
|
|
CurrentOrder = AllOrders.FirstOrDefault<OrderInfo>(x => x.POName == (i + 1).ToString("D7"));
|
|
|
|
/// The following replaces UpdatePiecesCount() call
|
|
targetGroupBox.Visible = false;
|
|
completedGroupBox.Visible = false;
|
|
completedGroupBox.BackColor = SystemColors.Control;
|
|
workflowComboBox.Enabled = true;
|
|
clearButton_Click(null, null);
|
|
return;
|
|
}
|
|
}
|
|
|
|
long orderNr;
|
|
OrderInfo order;
|
|
///
|
|
if (string.IsNullOrEmpty(orderComboBox.Text) ||
|
|
!long.TryParse(orderComboBox.Text, out orderNr) ||
|
|
orderNr <= Cnst.MaxPredefinedOrderNr ||
|
|
(order = orders.FirstOrDefault(x => x.POName == orderComboBox.Text)) == null)
|
|
{
|
|
CurrentOrder = null;
|
|
workflowComboBox.Enabled = true;
|
|
}
|
|
else
|
|
{
|
|
CurrentOrder = order;
|
|
if (UpdateWorkflowCombo(workflows, order.Workflow))
|
|
{
|
|
if (UpdateWorkstepCombo(CurrentWorkflow, workplaceTextBox.Text))
|
|
{
|
|
UpdateItems();
|
|
ClearBatchNumbers();
|
|
}
|
|
}
|
|
workflowComboBox.Enabled = false;
|
|
|
|
InitializeSNGeneratorPrinter();
|
|
}
|
|
|
|
UpdatePiecesCount();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine the next base number for the specified number generator
|
|
/// </summary>
|
|
/// <param name="allOrders">All orders (incl. OrderState.Finished ones)</param>
|
|
/// <param name="nrGeneratorIx">Number generator index (0 .. Cnst.NrGeneratorsCount - 1)</param>
|
|
/// <returns>Next base number</returns>
|
|
public int GetNextBaseNr(IList<OrderInfo> allOrders, int nrGeneratorIx)
|
|
{
|
|
int nextBaseNr = 0;
|
|
foreach (var o in allOrders)
|
|
{
|
|
int baseNr;
|
|
switch (nrGeneratorIx)
|
|
{
|
|
default:
|
|
case 0: baseNr = o.BaseNr1; break;
|
|
case 1: baseNr = o.BaseNr2; break;
|
|
case 2: baseNr = o.BaseNr3; break;
|
|
case 3: baseNr = o.BaseNr4; break;
|
|
case 4: baseNr = o.BaseNr5; break;
|
|
}
|
|
|
|
if (baseNr + o.PiecesCount + Cnst.ExtraPieces > nextBaseNr)
|
|
{
|
|
nextBaseNr = Math.Max(baseNr + o.PiecesCount + Cnst.ExtraPieces, Cnst.MinGeneratedNr);
|
|
}
|
|
}
|
|
|
|
return nextBaseNr;
|
|
}
|
|
|
|
private void orderComboBox_GotFocus(object sender, System.EventArgs e)
|
|
{
|
|
orderLabel.ForeColor = Color.White;
|
|
orderLabel.BackColor = Color.DarkBlue;
|
|
}
|
|
|
|
private void orderComboBox_LostFocus(object sender, System.EventArgs e)
|
|
{
|
|
orderLabel.ForeColor = SystemColors.ControlText;
|
|
orderLabel.BackColor = SystemColors.Control;
|
|
}
|
|
|
|
private void orderLabel_Click(object sender, EventArgs e)
|
|
{
|
|
orderComboBox.Focus();
|
|
}
|
|
}
|
|
}
|