コード例 #1
0
        public override void Record_RowPersisting(PXCache sender, PXRowPersistingEventArgs e)
        {
            if ((e.Operation & PXDBOperation.Command) == PXDBOperation.Insert && ((FSAddress)e.Row).IsDefaultAddress == true)
            {
                PXView view = sender.Graph.TypedViews.GetView(_DuplicateSelect, true);
                view.Clear();

                FSAddress previousAddress = (FSAddress)view.SelectSingle(((FSAddress)e.Row).BAccountID, ((FSAddress)e.Row).BAccountAddressID, ((FSAddress)e.Row).RevisionID);

                if (previousAddress != null)
                {
                    _KeyToAbort = sender.GetValue(e.Row, _RecordID);
                    object newKey = sender.Graph.Caches[typeof(FSAddress)].GetValue(previousAddress, _RecordID);

                    PXCache cache = sender.Graph.Caches[_ItemType];

                    foreach (object data in cache.Updated)
                    {
                        object dataKey = cache.GetValue(data, _FieldOrdinal);

                        if (Equals(_KeyToAbort, dataKey))
                        {
                            cache.SetValue(data, _FieldOrdinal, newKey);
                        }
                    }

                    _KeyToAbort = null;
                    e.Cancel    = true;
                    return;
                }
            }

            base.Record_RowPersisting(sender, e);
        }
コード例 #2
0
        protected virtual IAddressBase GetFromAddress(FSServiceOrder order)
        {
            FSAddress returnAdrress = PXSelectJoin <FSAddress,
                                                    InnerJoin <
                                                        FSBranchLocation,
                                                        On <FSBranchLocation.branchLocationAddressID, Equal <FSAddress.addressID> > >,
                                                    Where <
                                                        FSBranchLocation.branchLocationID, Equal <Required <FSBranchLocation.branchLocationID> > > >
                                      .Select(Base, order.BranchLocationID)
                                      .RowCast <FSAddress>()
                                      .FirstOrDefault();

            return(returnAdrress);
        }
コード例 #3
0
 public virtual IEnumerable ValidateAddress(PXAdapter adapter)
 {
     foreach (FSBranchLocation current in adapter.Get <FSBranchLocation>())
     {
         if (current != null)
         {
             FSAddress address = this.BranchLocation_Address.Select();
             if (address != null && address.IsDefaultAddress == false && address.IsValidated == false)
             {
                 PXAddressValidator.Validate <FSAddress>(this, address, true);
             }
         }
         yield return(current);
     }
 }
コード例 #4
0
        public override void RowPersisting(PXCache sender, PXRowPersistingEventArgs e)
        {
            object key = sender.GetValue(e.Row, _FieldOrdinal);

            if (key != null)
            {
                PXCache cache = sender.Graph.Caches[_RecordType];

                if (Convert.ToInt32(key) < 0)
                {
                    foreach (object data in cache.Inserted)
                    {
                        object dataKey = cache.GetValue(data, _RecordID);

                        if (Equals(key, dataKey))
                        {
                            if (((FSAddress)data).IsDefaultAddress == true)
                            {
                                PXView view = sender.Graph.TypedViews.GetView(_DuplicateSelect, true);
                                view.Clear();

                                FSAddress previousAddress = (FSAddress)view.SelectSingle(((FSAddress)data).BAccountID, ((FSAddress)data).BAccountAddressID, ((FSAddress)data).RevisionID);

                                if (previousAddress != null)
                                {
                                    _KeyToAbort = sender.GetValue(e.Row, _FieldOrdinal);
                                    object id = sender.Graph.Caches[typeof(FSAddress)].GetValue(previousAddress, _RecordID);
                                    sender.SetValue(e.Row, _FieldOrdinal, id);
                                }
                            }

                            break;
                        }
                    }
                }
            }

            base.RowPersisting(sender, e);
        }
コード例 #5
0
        /// <summary>
        /// Adds the Employee(s) belonging to the Appointment's Service Area as recipients in the Email template generated by Appointment.
        /// </summary>
        private static void AddGeoZoneStaffRecipient(AppointmentEntry graphAppointmentEntry, NotificationRecipient recSetup, RecipientList recipients)
        {
            List <FSGeoZoneEmp> geoZoneEmpList = new List <FSGeoZoneEmp>();

            FSAddress fsAddressRow = graphAppointmentEntry.ServiceOrder_Address.SelectSingle();

            if (fsAddressRow != null && fsAddressRow.PostalCode != null)
            {
                FSGeoZonePostalCode fsGeoZoneRow = StaffSelectionHelper.GetMatchingGeoZonePostalCode(graphAppointmentEntry, fsAddressRow.PostalCode);

                if (fsGeoZoneRow != null)
                {
                    var fsGeoZonePostalCodeSet = PXSelectJoin <FSGeoZonePostalCode,
                                                               InnerJoin <FSGeoZoneEmp,
                                                                          On <
                                                                              FSGeoZoneEmp.geoZoneID, Equal <FSGeoZonePostalCode.geoZoneID> > >,
                                                               Where <
                                                                   FSGeoZonePostalCode.postalCode, Equal <Required <FSGeoZonePostalCode.postalCode> > > >
                                                 .Select(graphAppointmentEntry, fsGeoZoneRow.PostalCode);

                    foreach (PXResult <FSGeoZonePostalCode, FSGeoZoneEmp> bqlResult in fsGeoZonePostalCodeSet)
                    {
                        geoZoneEmpList.Add((FSGeoZoneEmp)bqlResult);
                    }
                }
            }

            List <FSGeoZoneEmp> fsGeoZoneEmpGroupByEmployeeID = geoZoneEmpList.GroupBy(x => x.EmployeeID).Select(grp => grp.First()).ToList();

            if (fsGeoZoneEmpGroupByEmployeeID.Count > 0)
            {
                foreach (FSGeoZoneEmp fsGeoZoneEmpRow in fsGeoZoneEmpGroupByEmployeeID)
                {
                    AddEmployeeStaffRecipient(graphAppointmentEntry, fsGeoZoneEmpRow.EmployeeID, BAccountType.EmployeeType, recSetup, recipients);
                }
            }
        }
コード例 #6
0
        public static bool DefaultBLOCAddress <TAddress, TAddressID>(PXCache sender, string fieldName, object documentRow, object addressRow, object sourceRow)
            where TAddress : class, IBqlTable, IAddress, new()
            where TAddressID : IBqlField
        {
            bool addressFound = false;

            if (sourceRow != null)
            {
                FSAddress address = addressRow as FSAddress;

                if (address == null)
                {
                    address = PXSelect <FSAddress,
                                        Where <
                                            FSAddress.addressID, Equal <Required <TAddressID> > > >
                              .Select(sender.Graph, sender.GetValue(documentRow, fieldName));
                }

                if (PXResult.Unwrap <FSAddress>(sourceRow)?.AddressID == null || sender.GetValue(documentRow, fieldName) == null)
                {
                    if (address == null || address.AddressID > 0)
                    {
                        address = new FSAddress();
                    }

                    address.BAccountAddressID = PXResult.Unwrap <TAddress>(sourceRow).AddressID;
                    address.BAccountID        = PXResult.Unwrap <TAddress>(sourceRow).BAccountID;
                    address.RevisionID        = PXResult.Unwrap <TAddress>(sourceRow).RevisionID;
                    address.IsDefaultAddress  = true;
                    address.AddressLine1      = PXResult.Unwrap <TAddress>(sourceRow).AddressLine1;
                    address.AddressLine2      = PXResult.Unwrap <TAddress>(sourceRow).AddressLine2;
                    address.AddressLine3      = PXResult.Unwrap <TAddress>(sourceRow).AddressLine3;
                    address.City        = PXResult.Unwrap <TAddress>(sourceRow).City;
                    address.State       = PXResult.Unwrap <TAddress>(sourceRow).State;
                    address.PostalCode  = PXResult.Unwrap <TAddress>(sourceRow).PostalCode;
                    address.CountryID   = PXResult.Unwrap <TAddress>(sourceRow).CountryID;
                    address.IsValidated = PXResult.Unwrap <TAddress>(sourceRow).IsValidated;
                    addressFound        = address.BAccountAddressID != null && address.BAccountID != null && address.RevisionID != null;

                    if (address.AddressID == null)
                    {
                        address = (FSAddress)sender.Graph.Caches[typeof(FSAddress)].Insert(address);
                        sender.SetValue(documentRow, fieldName, address.AddressID);
                    }
                    else if (addressRow == null)
                    {
                        sender.Graph.Caches[typeof(FSAddress)].Update(address);
                    }
                }
                else
                {
                    if (address != null && address.AddressID < 0)
                    {
                        sender.Graph.Caches[typeof(FSAddress)].Delete(address);
                    }

                    sender.SetValue(documentRow, fieldName, PXResult.Unwrap <TAddress>(sourceRow).AddressID);
                    addressFound = PXResult.Unwrap <FSAddress>(sourceRow).AddressID != null;
                }
            }

            return(addressFound);
        }
コード例 #7
0
        public virtual void OptimizeRoutes(RoutesOptimizationProcess graph, FSAppointmentFilter filter, List <FSAppointmentFSServiceOrder> list, PXResultset <FSAppointmentStaffMember, CSCalendar> staffSelected)
        {
            RouteOptimizerClient client = new RouteOptimizerClient();

            SingleDayOptimizationInput requestBody = new SingleDayOptimizationInput();

            List <FSAppointment> processList = new List <FSAppointment>();

            FSSetup fsSetupRow = graph.SetupRecord.Current;

            requestBody.balanced = true;

            requestBody.vehicles  = new List <Vehicle>();
            requestBody.waypoints = new List <Waypoint>();

            string address = string.Empty;

            if (staffSelected != null && staffSelected.Count == 0)
            {
                throw new PXException(PXMessages.LocalizeFormatNoPrefix(TX.Error.SELECT_AT_LEAST_ONE_STAFF_MEMBER));
            }

            //Origin end Route location
            FSAddress fsAddressRow = PXSelectJoin <FSAddress,
                                                   InnerJoin <FSBranchLocation,
                                                              On <FSBranchLocation.branchLocationAddressID, Equal <FSAddress.addressID> > >,
                                                   Where <
                                                       FSBranchLocation.branchLocationID, Equal <Required <FSBranchLocation.branchLocationID> > > >
                                     .Select(graph, list[0].BranchLocationID);

            address = SharedFunctions.GetAddressForGeolocation(fsAddressRow.PostalCode,
                                                               fsAddressRow.AddressLine1,
                                                               fsAddressRow.AddressLine2,
                                                               fsAddressRow.City,
                                                               fsAddressRow.State,
                                                               fsAddressRow.CountryID);

            GLocation[] results = Geocoder.Geocode(address, fsSetupRow.MapApiKey);

            if (results.Length == 0)
            {
                throw new PXException(PXMessages.LocalizeFormatNoPrefix(TX.Error.MAPS_FAILED_REVERSE_ADRESS, TX.TableName.BRANCH_LOCATION));
            }

            CSCalendar csVendorCalendarRow = PXSelect <CSCalendar,
                                                       Where <CSCalendar.calendarID, Equal <Required <CSCalendar.calendarID> > > >
                                             .Select(graph, fsSetupRow.CalendarID);

            //Driver Logic
            foreach (PXResult <FSAppointmentStaffMember, CSCalendar> result in staffSelected)
            {
                FSAppointmentStaffMember staffRow = (FSAppointmentStaffMember)result;
                CSCalendar csCalendarRow          = (CSCalendar)result;

                Vehicle vehicleRow = new Vehicle()
                {
                    name   = staffRow.BAccountID.ToString(),
                    origin = new RouteLocation()
                    {
                        latitude = results[0].LatLng.Latitude, longitude = results[0].LatLng.Longitude
                    },
                    destination = new RouteLocation()
                    {
                        latitude = results[0].LatLng.Latitude, longitude = results[0].LatLng.Longitude
                    },
                    tags = new List <string>()
                    {
                        staffRow.BAccountID.ToString()
                    }
                };

                TimeWindow working    = graph.GetWorkingTimeWindow(staffRow.EmployeeSDEnabled == true ? csCalendarRow : csVendorCalendarRow, filter.StartDate);
                Break      lunchBreak = graph.GetBreakWindow(fsSetupRow);

                if (lunchBreak != null)
                {
                    vehicleRow.breaks = new List <Break>()
                    {
                        lunchBreak
                    };
                }

                if (working != null)
                {
                    vehicleRow.timeWindow = working;
                    requestBody.vehicles.Add(vehicleRow);
                }
            }

            if (requestBody.vehicles.Count == 0)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    FSAppointment fsAppointmentRow = list[i];
                    UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.NOT_ABLE);
                    graph.Appointments.Update(fsAppointmentRow);
                    PXProcessing <FSAppointmentFSServiceOrder> .SetError(i, PXMessages.LocalizeFormatNoPrefix(TX.Error.APPOINTMENT_COULD_NOT_BE_REACH_SERVICED_NO_DRIVER_AVAILABLE));
                }

                if (graph.Appointments.Cache.IsDirty == true)
                {
                    graph.Appointments.Cache.Persist(PXDBOperation.Update);
                }

                return;
            }

            //Existing Appointment Logic
            if (filter.Type == ID.Type_ROOptimization.UNASSIGNED_APP && staffSelected.Count() > 0)
            {
                List <object> args = new List <object>();

                BqlCommand fsAppointmentList = new Select2 <FSAppointment,
                                                            InnerJoin <FSServiceOrder,
                                                                       On <FSServiceOrder.sOID, Equal <FSAppointment.sOID> >,
                                                                       InnerJoin <FSAddress,
                                                                                  On <FSAddress.addressID, Equal <FSServiceOrder.serviceOrderAddressID> > > > >();

                if (filter.BranchID != null)
                {
                    fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSServiceOrder.branchID, Equal <Required <FSServiceOrder.branchID> > >));
                    args.Add(filter.BranchID);
                }

                if (filter.BranchLocationID != null)
                {
                    fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSServiceOrder.branchLocationID, Equal <Required <FSServiceOrder.branchLocationID> > >));
                    args.Add(filter.BranchLocationID);
                }

                if (filter.StartDate != null)
                {
                    fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSAppointment.scheduledDateTimeBegin, GreaterEqual <Required <FSAppointment.scheduledDateTimeBegin> > >));
                    args.Add(filter.StartDateWithTime);
                }

                if (filter.EndDateWithTime != null)
                {
                    fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSAppointment.scheduledDateTimeEnd, LessEqual <Required <FSAppointment.scheduledDateTimeEnd> > >));
                    args.Add(filter.EndDateWithTime);
                }

                if (staffSelected != null && staffSelected.Count() > 0)
                {
                    fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSAppointment.primaryDriver, In <Required <FSAppointment.primaryDriver> > >));

                    int[] staffResult = StaffMemberFilter.Select()
                                        .RowCast <FSAppointmentStaffMember>()
                                        .Where(_ => _.Selected == true)
                                        .Select(_ => _.BAccountID)
                                        .Cast <int>()
                                        .ToArray();

                    args.Add(staffResult);
                }

                PXView appointmentView = new PXView(graph, true, fsAppointmentList);

                var fsAppointmentSet = appointmentView.SelectMulti(args.ToArray());

                foreach (PXResult <FSAppointment, FSServiceOrder, FSAddress> row in fsAppointmentSet)
                {
                    FSAppointment fsAppointmentRow = (FSAppointment)row;
                    fsAddressRow = (FSAddress)row;

                    address = SharedFunctions.GetAddressForGeolocation(
                        fsAddressRow.PostalCode,
                        fsAddressRow.AddressLine1,
                        fsAddressRow.AddressLine2,
                        fsAddressRow.City,
                        fsAddressRow.State,
                        fsAddressRow.CountryID);


                    Waypoint wp = GetWaypointFromAppointment(fsSetupRow, fsAppointmentRow, address);

                    if (wp != null)
                    {
                        requestBody.waypoints.Add(wp);

                        processList.Add(fsAppointmentRow);
                    }
                    else
                    {
                        UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.ADDRESS_ERROR);
                        graph.Appointments.Update(fsAppointmentRow);
                    }
                }
            }

            //Appointment Logic
            for (int i = list.Count - 1; i >= 0; i--)
            {
                bool addressError = false;

                try
                {
                    address = SharedFunctions.GetAddressForGeolocation(
                        list[i].PostalCode,
                        list[i].AddressLine1,
                        list[i].AddressLine2,
                        list[i].City,
                        list[i].State,
                        list[i].CountryID);

                    Waypoint wp = GetWaypointFromAppointment(fsSetupRow, list[i], address);

                    if (wp != null)
                    {
                        requestBody.waypoints.Add(wp);
                        processList.Add(list[i]);
                    }
                    else
                    {
                        addressError = true;
                    }
                }
                catch
                {
                    addressError = true;
                }

                if (addressError == true)
                {
                    addressError = false;

                    FSAppointment fsAppointmentRow = list[i];
                    UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.ADDRESS_ERROR);
                    graph.Appointments.Update(fsAppointmentRow);
                    list.RemoveAt(i);

                    PXProcessing <FSAppointmentFSServiceOrder> .SetError(i, PXMessages.LocalizeFormatNoPrefix(TX.Error.MAPS_FAILED_REVERSE_ADRESS, TX.TableName.APPOINTMENT));
                }
            }

            if (graph.Appointments.Cache.IsDirty == true)
            {
                graph.Appointments.Cache.Persist(PXDBOperation.Update);
            }

            try
            {
                SingleDayOptimizationOutput responseObject = client.getSingleDayOptimization(fsSetupRow.ROWWApiEndPoint, fsSetupRow.ROWWLicensekey, requestBody);

                AppointmentEntry graphAppointmentEntry = PXGraph.CreateInstance <AppointmentEntry>();

                for (int i = 0; i < responseObject.routes.Count; i++)
                {
                    int assignedstaffID;
                    int.TryParse(responseObject.routes[i].vehicle.name, out assignedstaffID);
                    bool changeFlag = false;

                    for (int j = 1; j < responseObject.routes[i].steps.Count - 1; j++)
                    {
                        RouteOtimizer.RouteStep currentAppointment = responseObject.routes[i].steps[j];
                        int appointmentID;
                        int.TryParse(currentAppointment.waypoint.name, out appointmentID);

                        FSAppointment fsAppointmentListRow = processList.Find(x => x.AppointmentID == appointmentID);

                        var newBegin = convertSecToTime(currentAppointment.serviceStartTimeSec, fsAppointmentListRow.ScheduledDateTimeBegin);
                        var newEnd   = newBegin.AddSeconds(currentAppointment.departureTimeSec - currentAppointment.arrivalTimeSec);

                        UpdateAppointmentHeader(fsAppointmentListRow, ID.Status_ROOptimization.OPTIMIZED, j, null, newBegin, newEnd);

                        if (fsAppointmentListRow.PrimaryDriver != null)
                        {
                            graph.Appointments.Update(fsAppointmentListRow);
                            changeFlag = true;
                        }
                        else
                        {
                            fsAppointmentListRow.PrimaryDriver = assignedstaffID;

                            FSAppointment fsAppointmentRow = graphAppointmentEntry.AppointmentRecords.Current = graphAppointmentEntry.AppointmentRecords.Search <FSAppointment.refNbr>(
                                fsAppointmentListRow.RefNbr, fsAppointmentListRow.SrvOrdType);

                            UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.OPTIMIZED, j, assignedstaffID, newBegin, newEnd);

                            graphAppointmentEntry.AppointmentRecords.Update(fsAppointmentRow);

                            FSAppointmentEmployee fsAppointmentEmployeeRow_New = new FSAppointmentEmployee()
                            {
                                AppointmentID = fsAppointmentRow.AppointmentID,
                                EmployeeID    = assignedstaffID
                            };

                            fsAppointmentEmployeeRow_New = graphAppointmentEntry.AppointmentServiceEmployees.Insert(fsAppointmentEmployeeRow_New);

                            graphAppointmentEntry.Save.Press();
                        }
                    }

                    if (changeFlag == true)
                    {
                        graph.Appointments.Cache.Persist(PXDBOperation.Update);
                    }
                }

                foreach (OutputWaypoint wp in responseObject.unreachableWaypoints.Concat(responseObject.unreachedWaypoints).GroupBy(p => p.name).Select(g => g.First()).ToList())
                {
                    int appointmentID;
                    int.TryParse(wp.name, out appointmentID);

                    FSAppointment fsAppointmentRow = list.Find(x => x.AppointmentID == appointmentID);
                    if (fsAppointmentRow != null)
                    {
                        for (int i = 0; i < list.Count; i++)
                        {
                            if (fsAppointmentRow.AppointmentID == list[i].AppointmentID)
                            {
                                UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.NOT_ABLE);
                                graph.Appointments.Update(fsAppointmentRow);

                                PXProcessing <FSAppointmentFSServiceOrder> .SetError(i, PXMessages.LocalizeFormatNoPrefix(TX.Error.APPOINTMENT_COULD_NOT_BE_REACH_SERVICED));
                            }
                        }
                    }
                }

                graph.Appointments.Cache.Persist(PXDBOperation.Update);
            }
            catch (PXException e)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    FSAppointment fsAppointmentRow = list[i];
                    UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.NOT_ABLE);
                    graph.Appointments.Update(fsAppointmentRow);

                    PXProcessing <FSAppointmentFSServiceOrder> .SetError(i, PXMessages.LocalizeFormatNoPrefix(e.Message));
                }

                graph.Appointments.Cache.Persist(PXDBOperation.Update);
            }
        }
コード例 #8
0
        private static void ApplyChangesfromAddressInfo(ServiceOrderEntry graphServiceOrderEntry, CRAddress crAddressRow, FSAddress fsAddressRow, ref bool somethingChanged)
        {
            if (crAddressRow == null)
            {
                return;
            }

            if (fsAddressRow.AddressLine1 != crAddressRow.AddressLine1)
            {
                graphServiceOrderEntry.ServiceOrder_Address.SetValueExt <FSAddress.addressLine1>(fsAddressRow, crAddressRow.AddressLine1);
                somethingChanged = true;
            }

            if (fsAddressRow.AddressLine2 != crAddressRow.AddressLine2)
            {
                graphServiceOrderEntry.ServiceOrder_Address.SetValueExt <FSAddress.addressLine2>(fsAddressRow, crAddressRow.AddressLine2);
                somethingChanged = true;
            }

            if (fsAddressRow.AddressLine3 != crAddressRow.AddressLine3)
            {
                graphServiceOrderEntry.ServiceOrder_Address.SetValueExt <FSAddress.addressLine3>(fsAddressRow, crAddressRow.AddressLine3);
                somethingChanged = true;
            }

            if (fsAddressRow.City != crAddressRow.City)
            {
                graphServiceOrderEntry.ServiceOrder_Address.SetValueExt <FSAddress.city>(fsAddressRow, crAddressRow.City);
                somethingChanged = true;
            }

            if (fsAddressRow.CountryID != crAddressRow.CountryID)
            {
                graphServiceOrderEntry.ServiceOrder_Address.SetValueExt <FSAddress.countryID>(fsAddressRow, crAddressRow.CountryID);
                somethingChanged = true;
            }

            if (fsAddressRow.State != crAddressRow.State)
            {
                graphServiceOrderEntry.ServiceOrder_Address.SetValueExt <FSAddress.state>(fsAddressRow, crAddressRow.State);
                somethingChanged = true;
            }

            if (fsAddressRow.PostalCode != crAddressRow.PostalCode)
            {
                graphServiceOrderEntry.ServiceOrder_Address.SetValueExt <FSAddress.postalCode>(fsAddressRow, crAddressRow.PostalCode);
                somethingChanged = true;
            }
        }
コード例 #9
0
        public static void UpdateServiceOrderHeader(ServiceOrderEntry graphServiceOrderEntry,
                                                    PXCache cache,
                                                    CROpportunity crOpportunityRow,
                                                    FSCreateServiceOrderFilter fsCreateServiceOrderOnOpportunityFilterRow,
                                                    FSServiceOrder fsServiceOrderRow,
                                                    CRContact crContactRow,
                                                    CRAddress crAddressRow,
                                                    bool updatingExistingSO)
        {
            bool somethingChanged = false;

            FSSrvOrdType fsSrvOrdTypeRow = GetServiceOrderType(graphServiceOrderEntry, fsServiceOrderRow.SrvOrdType);

            if (fsSrvOrdTypeRow.Behavior != ID.Behavior_SrvOrderType.INTERNAL_APPOINTMENT)
            {
                if (fsServiceOrderRow.CustomerID != crOpportunityRow.BAccountID)
                {
                    graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.customerID>(fsServiceOrderRow, crOpportunityRow.BAccountID);
                    somethingChanged = true;
                }

                if (fsServiceOrderRow.LocationID != crOpportunityRow.LocationID)
                {
                    graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.locationID>(fsServiceOrderRow, crOpportunityRow.LocationID);
                    somethingChanged = true;
                }
            }

            if (fsServiceOrderRow.CuryID != crOpportunityRow.CuryID)
            {
                graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.curyID>(fsServiceOrderRow, crOpportunityRow.CuryID);
                somethingChanged = true;
            }

            if (fsServiceOrderRow.BranchID != crOpportunityRow.BranchID)
            {
                graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.branchID>(fsServiceOrderRow, crOpportunityRow.BranchID);
                somethingChanged = true;
            }

            if (fsServiceOrderRow.BranchLocationID != fsCreateServiceOrderOnOpportunityFilterRow.BranchLocationID)
            {
                graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.branchLocationID>(fsServiceOrderRow, fsCreateServiceOrderOnOpportunityFilterRow.BranchLocationID);
                somethingChanged = true;
            }

            if (fsServiceOrderRow.ContactID != crOpportunityRow.ContactID)
            {
                graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.contactID>(fsServiceOrderRow, crOpportunityRow.ContactID);
                somethingChanged = true;
            }

            if (fsServiceOrderRow.DocDesc != crOpportunityRow.Subject)
            {
                graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.docDesc>(fsServiceOrderRow, crOpportunityRow.Subject);
                somethingChanged = true;
            }

            if (fsServiceOrderRow.ProjectID != crOpportunityRow.ProjectID)
            {
                graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.projectID>(fsServiceOrderRow, crOpportunityRow.ProjectID);
                somethingChanged = true;
            }

            if (crOpportunityRow.OwnerID != null)
            {
                if (crOpportunityRow.OwnerID != (Guid?)cache.GetValueOriginal <CROpportunity.ownerID>(crOpportunityRow))
                {
                    int?salesPersonID = GetSalesPersonID(graphServiceOrderEntry, crOpportunityRow.OwnerID);

                    if (salesPersonID != null)
                    {
                        graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.salesPersonID>(fsServiceOrderRow, salesPersonID);
                        somethingChanged = true;
                    }
                }
            }

            if (fsServiceOrderRow.OrderDate != crOpportunityRow.CloseDate)
            {
                graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.orderDate>(fsServiceOrderRow, crOpportunityRow.CloseDate);
                somethingChanged = true;
            }

            FSAddress fsAddressRow = graphServiceOrderEntry.ServiceOrder_Address.Select();
            FSContact fsContactRow = graphServiceOrderEntry.ServiceOrder_Contact.Select();

            ApplyChangesfromContactInfo(graphServiceOrderEntry, crContactRow, fsContactRow, ref somethingChanged);
            ApplyChangesfromAddressInfo(graphServiceOrderEntry, crAddressRow, fsAddressRow, ref somethingChanged);

            if (fsServiceOrderRow.TaxZoneID != crOpportunityRow.TaxZoneID)
            {
                graphServiceOrderEntry.ServiceOrderRecords.SetValueExt <FSServiceOrder.taxZoneID>(fsServiceOrderRow, crOpportunityRow.TaxZoneID);
                somethingChanged = true;
            }

            if (somethingChanged && updatingExistingSO)
            {
                graphServiceOrderEntry.ServiceOrderRecords.Update(fsServiceOrderRow);
            }
        }