public string RefreshSmartsheetToken()
        {
            Guid loggedUser = PXAccess.GetUserID();

            Users usersRow = PXSelect <Users,
                                       Where <Users.pKID, Equal <Required <Users.pKID> > > >
                             .Select(this.Base, loggedUser);

            UsersSSExt usersSSExtRow = PXCache <Users> .GetExtension <UsersSSExt>(usersRow);

            PMSetup setupRow = PXSelect <PMSetup> .Select(this.Base);

            PMSetupSSExt setupSSExtRow = PXCache <PMSetup> .GetExtension <PMSetupSSExt>(setupRow);

            if (usersSSExtRow != null && usersSSExtRow.UsrSmartsheetRefreshToken != null)
            {
                List <string> ssToken = refreshToken(setupSSExtRow.UsrSmartsheetClientID, setupSSExtRow.UsrSmartsheetAppSecret, usersSSExtRow.UsrSmartsheetRefreshToken);

                if (ssToken.Count == 2)
                {
                    usersSSExtRow.UsrSmartsheetToken        = ssToken[0];
                    usersSSExtRow.UsrSmartsheetRefreshToken = ssToken[1];
                    this.Base.UserProfile.Update(usersRow);
                    this.Base.Actions.PressSave();

                    return(usersSSExtRow.UsrSmartsheetToken);
                }
            }

            return("");
        }
        protected virtual void RequestSSToken()
        {
            PMSetup pmSetupRow = PXSelect <PMSetup> .Select(Base);

            PMSetupSSExt pmSetupSSExtRow = PXCache <PMSetup> .GetExtension <PMSetupSSExt>(pmSetupRow);

            string loginScopeCompany = PXDatabase.Companies.Length > 0 ? PXAccess.GetCompanyName() : String.Empty;
            string currentScope      = String.Format(",{0},{1}", Base.Accessinfo.UserName, loginScopeCompany);

            if (pmSetupSSExtRow != null && pmSetupSSExtRow.UsrSmartsheetClientID != null)
            {
                string smartsheetRedirect = SmartsheetConstants.SSCodeRequest.ENDPOINT;
                smartsheetRedirect += SmartsheetConstants.SSCodeRequest.RESPONSE_TYPE;
                smartsheetRedirect += SmartsheetConstants.SSCodeRequest.CLIENT_ID + pmSetupSSExtRow.UsrSmartsheetClientID;
                smartsheetRedirect += SmartsheetConstants.SSCodeRequest.SCOPE;
                smartsheetRedirect += SmartsheetConstants.SSCodeRequest.STATE + currentScope;

                throw new PXRedirectToUrlException(smartsheetRedirect, PXBaseRedirectException.WindowMode.InlineWindow,
                                                   string.Empty, false);
            }
            else
            {
                throw new PXException(SmartsheetConstants.Messages.SMARTSHEET_ID_MISSING);
            }
        }
        public virtual void loadTemplateColumnsSS()
        {
            PMSetup pmSetupRow = this.Base.Setup.Current;

            if (pmSetupRow == null)
            {
                throw new PXException(SmartsheetConstants.Messages.ERROR_SETUP);
            }

            PXCache <PMSSMapping> mappingCache = this.Base.Caches <PMSSMapping>();

            if (MappingSetup.Select().Count() == 0)
            {
                InsertTemplate(mappingCache);
            }
            else
            {
                WebDialogResult result = this.Base.Setup.View.Ask(this.Base.Setup.Current, SmartsheetConstants.Messages.CONFIRM_HEADER, SmartsheetConstants.Messages.CONFIRM_RELOAD_VALUES, MessageButtons.YesNoCancel, MessageIcon.Warning);

                if (result == WebDialogResult.Yes)
                {
                    foreach (PMSSMapping item in MappingSetup.Select())
                    {
                        mappingCache.Delete(item);
                    }
                    mappingCache.Persist(PXDBOperation.Delete);
                    InsertTemplate(mappingCache);
                }
            }
        }
        protected virtual void PMTemplateListSS_TemplateDefault_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
        {
            PMTemplateListSS row = e.Row as PMTemplateListSS;

            if (row == null || row.TemplateDefault == null)
            {
                return;
            }

            PMSetup      setupRecord  = this.Base.Setup.Current as PMSetup;
            PMSetupSSExt pmSetupSSExt = PXCache <PMSetup> .GetExtension <PMSetupSSExt>(setupRecord);

            if ((bool)row.TemplateDefault)
            {
                PMTemplateListSS pmSSMappingRecord = this.TemplateSetup.Select().RowCast <PMTemplateListSS>().Where(_ => (bool)_.TemplateDefault == true && _.TemplateSS != row.TemplateSS).FirstOrDefault();
                if (pmSSMappingRecord != null)
                {
                    pmSSMappingRecord.TemplateDefault = false;
                }
                pmSetupSSExt.UsrSSTemplate = row.TemplateSS;
            }
            else
            {
                pmSetupSSExt.UsrSSTemplate = null;
            }
            this.Base.Setup.Update(setupRecord);
            TemplateSetup.View.RequestRefresh();
        }
Пример #5
0
        protected virtual void AutoAllocateTasks(List <PMTask> tasks)
        {
            PMSetup setup = PXSelect <PMSetup> .Select(Base);

            bool autoreleaseAllocation = setup.AutoReleaseAllocation == true;

            PMAllocator allocator = PXGraph.CreateInstance <PMAllocator>();

            allocator.Clear();
            allocator.TimeStamp = Base.TimeStamp;
            allocator.Execute(tasks);
            allocator.Actions.PressSave();

            if (allocator.Document.Current != null && autoreleaseAllocation)
            {
                List <PMRegister> list = new List <PMRegister>();
                list.Add(allocator.Document.Current);
                List <ProcessInfo <Batch> > batchList;
                bool releaseSuccess = RegisterRelease.ReleaseWithoutPost(list, false, out batchList);
                if (!releaseSuccess)
                {
                    throw new PXException(PM.Messages.AutoReleaseFailed);
                }
                foreach (var item in batchList)
                {
                    Base.created.AddRange(item.Batches);
                }
            }
        }
Пример #6
0
        protected virtual void PMSetup_RowPersisting(PXCache sender, PXRowPersistingEventArgs e)
        {
            if (e.Row == null)
            {
                return;
            }

            PMSetup      pmSetupRow      = (PMSetup)e.Row;
            PMSetupSSExt pmSetupSSExtRow = PXCache <PMSetup> .GetExtension <PMSetupSSExt>(pmSetupRow);

            if (pmSetupSSExtRow.UsrSmartsheetClientID != null &&
                String.IsNullOrEmpty(pmSetupSSExtRow.UsrDefaultRateTableID))
            {
                throw new PXRowPersistingException(typeof(PMSetupSSExt.usrDefaultRateTableID).Name, null,
                                                   ErrorMessages.FieldIsEmpty);
            }
        }
        protected virtual void PMSetup_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
        {
            if (e.Row == null)
            {
                return;
            }

            PMSetup pmSetup = e.Row as PMSetup;

            Dictionary <string, string> fields = new Dictionary <string, string>();

            foreach (PMTemplateListSS templateRow in TemplateSetup.Select())
            {
                fields.Add(templateRow.TemplateSS, templateRow.TemplateName);
            }
            PXStringListAttribute.SetList <PMSetupSSExt.usrSSTemplate>(cache, pmSetup, fields.Keys.ToArray(), fields.Values.ToArray());
        }
        protected virtual IEnumerable PopulateDates(PXAdapter adapter)
        {
            PMSetup      setupRecord    = this.Base.Setup.Select();
            PMSetupSSExt setupRecordExt = PXCache <PMSetup> .GetExtension <PMSetupSSExt>(setupRecord);

            if (!String.IsNullOrEmpty(setupRecordExt.UsrTypeTaskDate) && setupRecordExt.UsrDurationTaskDate != null)
            {
                foreach (PMTask filter in this.Base.Tasks.Select())
                {
                    PMTaskSSExt pMTaskRecordExt = PXCache <PMTask> .GetExtension <PMTaskSSExt>(filter);

                    if (String.IsNullOrEmpty(filter.StartDate.ToString()))
                    {
                        filter.StartDate = DateTime.Today;
                    }
                    if (String.IsNullOrEmpty(filter.EndDate.ToString()))
                    {
                        switch (setupRecordExt.UsrTypeTaskDate)
                        {
                        case SmartsheetConstants.SSConstants.DAY:
                            SmartsheetHelper smartSheetHelperObject = new SmartsheetHelper();
                            filter.EndDate = smartSheetHelperObject.CalculateWorkingDays((DateTime)filter.StartDate, (int)setupRecordExt.UsrDurationTaskDate);
                            break;

                        case SmartsheetConstants.SSConstants.MONTH:
                            filter.EndDate = ((DateTime)filter.StartDate).AddMonths((int)setupRecordExt.UsrDurationTaskDate);
                            break;

                        case SmartsheetConstants.SSConstants.YEAR:
                            filter.EndDate = ((DateTime)filter.StartDate).AddYears((int)setupRecordExt.UsrDurationTaskDate);
                            break;
                        }
                    }
                    this.Base.Tasks.Cache.Update(filter);
                }
            }
            else
            {
                throw new PXException(SmartsheetConstants.Messages.DURATION_FIELDS_NOT_INDICATED);
            }

            return(adapter.Get());
        }
        public virtual void loadTemplateSS()
        {
            PMSetup pmSetupRow = this.Base.Setup.Current;
            Dictionary <string, string> templateSS          = GetTemplateSS();
            PXCache <PMTemplateListSS>  pmtemplateListCache = this.Base.Caches <PMTemplateListSS>();

            foreach (PMTemplateListSS item in TemplateSetup.Select())
            {
                pmtemplateListCache.Delete(item);
            }

            foreach (var templateRow in templateSS)
            {
                PMTemplateListSS ci = (PMTemplateListSS)pmtemplateListCache.Insert(new PMTemplateListSS
                {
                    TemplateSS      = templateRow.Key.ToString(),
                    TemplateName    = templateRow.Value.ToString(),
                    TemplateDefault = false
                });
            }
        }
        public void GetSmartsheetToken(string currentURL)
        {
            Guid loggedUser = Base.Accessinfo.UserID;

            Users usersRow = PXSelect <Users,
                                       Where <Users.pKID, Equal <Required <Users.pKID> > > >
                             .Select(this.Base, loggedUser);

            UsersSSExt usersSSExtRow = PXCache <Users> .GetExtension <UsersSSExt>(usersRow);

            this.Base.UserProfile.Current = this.Base.UserProfile.Search <Users.pKID>(usersRow.PKID);

            PMSetup setupRow = PXSelect <PMSetup> .Select(this.Base);

            PMSetupSSExt setupSSExtRow = PXCache <PMSetup> .GetExtension <PMSetupSSExt>(setupRow);

            if (currentURL.IndexOf(SmartsheetConstants.SSCodeRequest.STATE, StringComparison.CurrentCultureIgnoreCase) > 0)
            {
                string ssCode = getSSCodeString(currentURL);

                if (ssCode.Trim().Length > 0)
                {
                    List <string> ssToken = getSSToken(setupSSExtRow.UsrSmartsheetClientID, ssCode, setupSSExtRow.UsrSmartsheetAppSecret);

                    if (ssToken.Count == 2)
                    {
                        usersSSExtRow.UsrSmartsheetToken        = ssToken[0];
                        usersSSExtRow.UsrSmartsheetRefreshToken = ssToken[1];
                        this.Base.UserProfile.Update(usersRow);
                        this.Base.Actions.PressSave();
                    }
                }
            }
            SendRefreshCall();

            return;
        }
        /// <summary>
        /// Verifies the connection Token and the existence of the Sheet
        /// </summary>
        /// <param name="projectEntryGraph">Project's Graph</param>
        /// <param name="pmProjectRow">Current PMProject row</param>
        /// <param name="refreshedToken">Existing token</param>
        /// <param name="isMassProcess">Indicates if it's used in a processing page</param>
        /// <returns></returns>
        public SmartsheetClient CheckTokenSheetSS(ProjectEntry projectEntryGraph, PMProject pmProjectRow, string refreshedToken = "", bool isMassProcess = false)
        {
            //Primary Data View is set
            projectEntryGraph.Project.Current = pmProjectRow;

            SmartsheetHelper smartSheetHelperObject = new SmartsheetHelper();

            string sheetName = pmProjectRow.ContractCD.Trim() + " - " + pmProjectRow.Description.Trim();

            sheetName = smartSheetHelperObject.Left(sheetName, SmartsheetConstants.SSConstants.SS_PROJECT_NAME_LENGTH);

            PMSetup      setupRecord  = projectEntryGraph.Setup.Select();
            PMSetupSSExt pmSetupSSExt = PXCache <PMSetup> .GetExtension <PMSetupSSExt>(setupRecord);

            PMProjectSSExt pmProjectSSExt = PXCache <PMProject> .GetExtension <PMProjectSSExt>(pmProjectRow);

            Users userRecord = PXSelect <
                Users,
                Where <Users.pKID, Equal <Required <AccessInfo.userID> > > >
                               .Select(projectEntryGraph, projectEntryGraph.Accessinfo.UserID);

            UsersSSExt userRecordSSExt = PXCache <Users> .GetExtension <UsersSSExt>(userRecord);

            smartSheetHelperObject.SetupValidation(userRecordSSExt, pmSetupSSExt);
            smartSheetHelperObject.ProjectValidation(projectEntryGraph);

            Token token = new Token();

            token.AccessToken = (String.IsNullOrEmpty(refreshedToken)) ? userRecordSSExt.UsrSmartsheetToken : refreshedToken;

            try
            {
                SmartsheetClient smartsheetClient = new SmartsheetBuilder()
                                                    .SetAccessToken(token.AccessToken)
                                                    .SetDateTimeFixOptOut(true)
                                                    .Build();

                long?sheetSelected;
                Dictionary <string, long> currentColumnMap = new Dictionary <string, long>();

                if (pmProjectSSExt != null &&
                    pmProjectSSExt.UsrSmartsheetContractID != null)        //Acumatica Project is already linked to SS
                {
                    sheetSelected = pmProjectSSExt.UsrSmartsheetContractID;

                    Sheet ssProjectSheet = smartsheetClient.SheetResources.GetSheet((long)sheetSelected, null, null, null, null, null, null, null);
                }

                return(smartsheetClient);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains(SmartsheetConstants.SSConstants.EXPIRED_TOKEN_MESSAGE))
                {
                    MyProfileMaint    profileMaintGraph = PXGraph.CreateInstance <MyProfileMaint>();
                    MyProfileMaintExt graphExtended     = profileMaintGraph.GetExtension <MyProfileMaintExt>();
                    string            updatedToken      = graphExtended.RefreshSmartsheetToken();
                    CheckTokenSheetSS(projectEntryGraph, pmProjectRow, updatedToken);
                }

                if (ex.Message.Contains(SmartsheetConstants.SSConstants.NOTFOUND_PROJECT_MESSAGE))
                {
                    if (isMassProcess)
                    {
                        SmartsheetClient smartsheetClient = new SmartsheetBuilder()
                                                            .SetAccessToken(token.AccessToken)
                                                            .SetDateTimeFixOptOut(true)
                                                            .Build();
                        UnlinkSmartsheetProject(projectEntryGraph);
                        CreateUpdateGanttProject(projectEntryGraph, pmProjectRow, smartsheetClient, true);
                    }
                    else
                    {
                        UnlinkSmartsheetProject(projectEntryGraph);
                        throw new PXException(SmartsheetConstants.Messages.UNLINK_PROJECT);
                    }
                }
                else
                {
                    throw new PXException(ex.Message);
                }

                return(null);
            }
        }
        /// <summary>
        /// Creates or updates the Smartsheet project with information from Acumatica.
        /// New Tasks created in Smartsheet will be updated back in Acumatica
        /// </summary>
        /// <param name="projectEntryGraph">Project Entry graph</param>
        /// <param name="pmProjectRow">PMProject record</param>
        /// <param name="smartsheetClient">Smartsheet's SDK Client</param>
        /// <param name="isMassProcess">Indicates if it's used in a processing page</param>
        public void CreateUpdateGanttProject(ProjectEntry projectEntryGraph, PMProject pmProjectRow, SmartsheetClient smartsheetClient, bool isMassProcess = false)
        {
            //Primary Data View is set
            projectEntryGraph.Project.Current = pmProjectRow;
            PMProjectSSExt pmProjectSSExt = PXCache <PMProject> .GetExtension <PMProjectSSExt>(pmProjectRow);

            PMSetup      setupRecord  = projectEntryGraph.Setup.Select();
            PMSetupSSExt pmSetupSSExt = PXCache <PMSetup> .GetExtension <PMSetupSSExt>(setupRecord);

            SmartsheetHelper smartSheetHelperObject = new SmartsheetHelper();

            if (String.IsNullOrEmpty(pmProjectSSExt.UsrTemplateSS))
            {
                throw new PXException(SmartsheetConstants.Messages.DEFAULT_TEMPLATE);
            }

            string sheetName = pmProjectRow.ContractCD.Trim() + " - " + pmProjectRow.Description.Trim();

            sheetName = smartSheetHelperObject.Left(sheetName, SmartsheetConstants.SSConstants.SS_PROJECT_NAME_LENGTH);

            try
            {
                long?sheetSelected;
                Dictionary <string, long> currentColumnMap = new Dictionary <string, long>();

                //////////////////
                //Information from Acumatica is updated in Smartsheet
                //////////////////

                PXResultset <PMSSMapping> templateMappingSet = PXSelect <
                    PMSSMapping,
                    Where <PMSSMapping.templateSS, Equal <Required <PMSSMapping.templateSS> > > >
                                                               .Select(projectEntryGraph, pmProjectSSExt.UsrTemplateSS);

                if (pmProjectSSExt != null &&
                    pmProjectSSExt.UsrSmartsheetContractID != null)        //Acumatica Project is already linked to SS
                {
                    sheetSelected = pmProjectSSExt.UsrSmartsheetContractID;

                    Sheet ssProjectSheet = smartsheetClient.SheetResources.GetSheet((long)sheetSelected, null, null, null, null, null, null, null);

                    //Columns ID Mapping
                    currentColumnMap = new Dictionary <string, long>();
                    foreach (Column currentColumn in ssProjectSheet.Columns)
                    {
                        currentColumnMap.Add(currentColumn.Title, (long)currentColumn.Id);
                    }

                    smartSheetHelperObject.UpdateSSProject(smartsheetClient, currentColumnMap, projectEntryGraph, sheetSelected, smartSheetHelperObject, templateMappingSet);
                }
                else //Acumatica Project has not been linked to Smartsheet
                {
                    //Sheet is created from a the template selected in the Project
                    Sheet sheet = new Sheet.CreateSheetFromTemplateBuilder(sheetName, Convert.ToInt64(pmProjectSSExt.UsrTemplateSS)).Build();
                    sheet = smartsheetClient.SheetResources.CreateSheet(sheet);

                    Sheet newlyCreatedSheet = smartsheetClient.SheetResources.GetSheet((long)sheet.Id, null, null, null, null, null, null, null);

                    currentColumnMap = new Dictionary <string, long>();
                    foreach (Column currentColumn in newlyCreatedSheet.Columns)
                    {
                        currentColumnMap.Add(currentColumn.Title, (long)currentColumn.Id);
                    }

                    //Acumatica Tasks are added as Smartsheet rows
                    List <Row>  newSSRows = smartSheetHelperObject.InsertAcumaticaTasksInSS(projectEntryGraph, currentColumnMap, null, true, templateMappingSet);
                    IList <Row> ssRows    = smartsheetClient.SheetResources.RowResources.AddRows((long)sheet.Id, newSSRows);

                    int ssTaskIDPosition = 0;
                    if (ssRows.Count > 0 && ssRows[0].Cells != null)
                    {
                        PMSSMapping mappingSS = templateMappingSet.Where(t => ((PMSSMapping)t).NameAcu.Trim().ToUpper() == SmartsheetConstants.ColumnMapping.TASKS_CD.Trim().ToUpper()).FirstOrDefault();

                        ssTaskIDPosition = smartSheetHelperObject.GetSSTaskPosition(ssRows[0].Cells, currentColumnMap[mappingSS.NameSS]);
                    }

                    // Add SubTasks
                    smartSheetHelperObject.InsertAcumaticaSubTasks(projectEntryGraph, smartsheetClient, sheet, ssRows, smartSheetHelperObject, currentColumnMap, ssTaskIDPosition, templateMappingSet);

                    foreach (Row currentRow in ssRows)
                    {
                        foreach (PMTask rowTask in projectEntryGraph.Tasks.Select())
                        {
                            if (currentRow.Cells[ssTaskIDPosition].Value != null &&
                                rowTask.TaskCD != null &&
                                string.Equals(currentRow.Cells[ssTaskIDPosition].Value.ToString().Trim(), rowTask.TaskCD.Trim(), StringComparison.OrdinalIgnoreCase))
                            {
                                PMTaskSSExt pmTaskSSExtRow = PXCache <PMTask> .GetExtension <PMTaskSSExt>(rowTask);

                                pmTaskSSExtRow.UsrSmartsheetTaskID = currentRow.Id;
                                projectEntryGraph.Tasks.Update(rowTask);
                                break;
                            }
                        }
                    }

                    sheetSelected = (long)sheet.Id;

                    PMProjectSSExt pmProjectSSExtRow = PXCache <PMProject> .GetExtension <PMProjectSSExt>(pmProjectRow);

                    pmProjectSSExtRow.UsrSmartsheetContractID = sheetSelected;
                    projectEntryGraph.Project.Update(pmProjectRow);
                }


                //////////////////
                //Information from Smartsheet is updated in Acumatica
                //////////////////
                Sheet updatedSheet = smartsheetClient.SheetResources.GetSheet((long)sheetSelected, null, null, null, null, null, null, null);

                int columnPosition = 0;
                Dictionary <string, int> columnPositionMap = new Dictionary <string, int>();
                foreach (Column currentColumn in updatedSheet.Columns)
                {
                    columnPositionMap.Add(currentColumn.Title, columnPosition);
                    columnPosition += 1;
                }

                smartSheetHelperObject.UpdateAcumaticaTasks(projectEntryGraph, pmProjectRow, pmSetupSSExt, updatedSheet, columnPositionMap, templateMappingSet);

                projectEntryGraph.Actions.PressSave();

                if (isMassProcess)
                {
                    PXProcessing.SetInfo(String.Format(SmartsheetConstants.Messages.SUCCESSFULLY_SYNCED, pmProjectRow.ContractCD));
                }
            }
            catch (Exception e)
            {
                throw new PXException(e.Message);
            }
        }
Пример #13
0
        /// <summary>
        /// Creates or updates the Smartsheet project with information from Acumatica.
        /// New Tasks created in Smartsheet will be updated back in Acumatica
        /// </summary>
        /// <param name="projectEntryGraph">Project Entry graph</param>
        /// <param name="pmProjectRow">PMProject record</param>
        /// <param name="isMassProcess">Indicates if it's used in a processing page</param>
        public void CreateUpdateGanttProject(ProjectEntry projectEntryGraph, PMProject pmProjectRow, string refreshedToken = "", bool isMassProcess = false)
        {
            //Primary Data View is set
            projectEntryGraph.Project.Current = pmProjectRow;

            SmartsheetHelper smartSheetHelperObject = new SmartsheetHelper();

            string sheetName = pmProjectRow.ContractCD.Trim() + " - " + pmProjectRow.Description.Trim();

            sheetName = smartSheetHelperObject.Left(sheetName, SmartsheetConstants.SSConstants.SS_PROJECT_NAME_LENGTH);

            PMSetup      setupRecord  = projectEntryGraph.Setup.Select();
            PMSetupSSExt pmSetupSSExt = PXCache <PMSetup> .GetExtension <PMSetupSSExt>(setupRecord);

            PMProjectSSExt pmProjectSSExt = PXCache <PMProject> .GetExtension <PMProjectSSExt>(pmProjectRow);

            Users userRecord = PXSelect <Users, Where <Users.pKID, Equal <Current <AccessInfo.userID> > > > .Select(projectEntryGraph);

            UsersSSExt userRecordSSExt = PXCache <Users> .GetExtension <UsersSSExt>(userRecord);

            smartSheetHelperObject.SetupValidation(userRecordSSExt, pmSetupSSExt);
            smartSheetHelperObject.ProjectValidation(projectEntryGraph);

            try
            {
                Token token = new Token();

                token.AccessToken = (String.IsNullOrEmpty(refreshedToken)) ? userRecordSSExt.UsrSmartsheetToken : refreshedToken;

                SmartsheetClient smartsheetClient = new SmartsheetBuilder().SetAccessToken(token.AccessToken).Build();

                long?sheetSelected;
                Dictionary <string, long> currentColumnMap = new Dictionary <string, long>();

                //////////////////
                //Information from Acumatica is updated in Smartsheet
                //////////////////
                if (pmProjectSSExt != null &&
                    pmProjectSSExt.UsrSmartsheetContractID != null)        //Acumatica Project is already linked to SS
                {
                    sheetSelected = pmProjectSSExt.UsrSmartsheetContractID;

                    Sheet ssProjectSheet = smartsheetClient.SheetResources.GetSheet((long)sheetSelected, null, null, null, null, null, null, null);

                    //Columns ID Mapping
                    currentColumnMap = new Dictionary <string, long>();
                    foreach (Column currentColumn in ssProjectSheet.Columns)
                    {
                        currentColumnMap.Add(currentColumn.Title, (long)currentColumn.Id);
                    }

                    smartSheetHelperObject.UpdateSSProject(smartsheetClient, currentColumnMap, projectEntryGraph, sheetSelected, smartSheetHelperObject);
                }
                else //Acumatica Project has not been linked to Smartsheet
                {
                    //Sheet is created from a Gantt Template available in SmartSheet
                    Sheet sheet = new Sheet.CreateSheetFromTemplateBuilder(sheetName, SmartsheetConstants.SSConstants.BASIC_SS_PROJECT_WITH_GANTT).Build();
                    sheet = smartsheetClient.SheetResources.CreateSheet(sheet);

                    Sheet newlyCreatedSheet = smartsheetClient.SheetResources.GetSheet((long)sheet.Id, null, null, null, null, null, null, null);

                    currentColumnMap = new Dictionary <string, long>();
                    foreach (Column currentColumn in newlyCreatedSheet.Columns)
                    {
                        currentColumnMap.Add(currentColumn.Title, (long)currentColumn.Id);
                    }

                    smartSheetHelperObject.AdjustGanttSheet(smartsheetClient, sheet, currentColumnMap);

                    //Acumatica Tasks are added as Smartsheet rows
                    List <Row>  newSSRows = smartSheetHelperObject.InsertAcumaticaTasksInSS(projectEntryGraph, currentColumnMap, null, true);
                    IList <Row> ssRows    = smartsheetClient.SheetResources.RowResources.AddRows((long)sheet.Id, newSSRows);

                    int ssTaskIDPosition = 0;
                    if (ssRows.Count > 0 && ssRows[0].Cells != null)
                    {
                        ssTaskIDPosition = smartSheetHelperObject.GetSSTaskPosition(ssRows[0].Cells, currentColumnMap[SmartsheetConstants.GanttTemplateMapping.TASK_NAME]);
                    }

                    smartSheetHelperObject.InsertAcumaticaSubTasks(projectEntryGraph, smartsheetClient, sheet, ssRows, smartSheetHelperObject, currentColumnMap, ssTaskIDPosition);

                    foreach (Row currentRow in ssRows)
                    {
                        foreach (PMTask rowTask in projectEntryGraph.Tasks.Select())
                        {
                            if (currentRow.Cells[ssTaskIDPosition].Value != null &&
                                rowTask.TaskCD != null &&
                                string.Equals(currentRow.Cells[ssTaskIDPosition].Value.ToString().Trim(), rowTask.TaskCD.Trim(), StringComparison.OrdinalIgnoreCase))
                            {
                                PMTaskSSExt pmTaskSSExtRow = PXCache <PMTask> .GetExtension <PMTaskSSExt>(rowTask);

                                pmTaskSSExtRow.UsrSmartsheetTaskID = currentRow.Id;
                                projectEntryGraph.Tasks.Update(rowTask);
                                break;
                            }
                        }
                    }

                    sheetSelected = (long)sheet.Id;

                    PMProjectSSExt pmProjectSSExtRow = PXCache <PMProject> .GetExtension <PMProjectSSExt>(pmProjectRow);

                    pmProjectSSExtRow.UsrSmartsheetContractID = sheetSelected;
                    projectEntryGraph.Project.Update(pmProjectRow);
                }


                //////////////////
                //Information from Smartsheet is updated in Acumatica
                //////////////////
                Sheet updatedSheet = smartsheetClient.SheetResources.GetSheet((long)sheetSelected, null, null, null, null, null, null, null);

                int columnPosition = 0;
                Dictionary <string, int> columnPositionMap = new Dictionary <string, int>();
                foreach (Column currentColumn in updatedSheet.Columns)
                {
                    columnPositionMap.Add(currentColumn.Title, columnPosition);
                    columnPosition += 1;
                }

                smartSheetHelperObject.UpdateAcumaticaTasks(projectEntryGraph, pmProjectRow, pmSetupSSExt, updatedSheet, columnPositionMap);

                projectEntryGraph.Actions.PressSave();

                if (isMassProcess)
                {
                    PXProcessing.SetInfo(String.Format(SmartsheetConstants.Messages.SUCCESSFULLY_SYNCED, pmProjectRow.ContractCD));
                }
            }
            catch (Exception e)
            {
                if (e.Message.Contains(SmartsheetConstants.SSConstants.EXPIRED_TOKEN_MESSAGE))
                {
                    MyProfileMaint    profileMaintGraph = PXGraph.CreateInstance <MyProfileMaint>();
                    MyProfileMaintExt graphExtended     = profileMaintGraph.GetExtension <MyProfileMaintExt>();
                    string            updatedToken      = graphExtended.RefreshSmartsheetToken();
                    CreateUpdateGanttProject(projectEntryGraph, pmProjectRow, updatedToken, isMassProcess = false);
                }
                else
                {
                    throw new PXException(e.Message);
                }
            }
        }