locked
Purchase Invoice visibility RRS feed

  • Question

  • I have created a purchase Invoice in Parent Business Unit, on creation the child business unit is selected in the form, so I have a doubt here, can I see a invoice created by user in Parent BU by selecting Child BU in the form(as said earlier),

    from Invoice area in user from Child BU(note: here we are not assigning or sharing the particular invoice to any user/team),

    Can any one please help me with this,

    I just wanted to know whether it is out of box functionality or this can be acheived by some sort of customizations???


    Vinod P

    Tuesday, August 6, 2013 8:13 AM

All replies

  • I am completely lost. Can you explain your problem again?

    You have created a record in 1 business unit, and are asking if users in child business units will have access? The answer is only if the users are given Organisation level access to Purchase Orders.

    Not sure what you're highlighting the 'Store' lookup for though, or what you mean by 'selecting child business unit on the form'.

    Paul


    If my response helped you find your answer please show your thanks by taking the time to "Mark As Answer" and "Vote As Helpful".

    Twitter LinkedIn Facebook Blog Magnetism

    Saturday, August 10, 2013 3:15 AM
  • Hai Paul,

    My Question is 

    can a user from child business unit see the record which is created by a parent business unit user, with the record not being shared or assigned to the particular child BU user. one more condition here is there are multiple child Business units in our case and there is a restriction that one child BU's record shouldn't be visible to other child BU, so here we can't give organisation level access to the purchase order entity, as above mentioned condition will not be satisfied.

    can you tell me whether this is possible through any customization, if so suggest me on how to do this???


    Vinod P

    Saturday, August 10, 2013 4:32 AM
  • Right, I understand now.

    This is not possible with out of the box security, as by default you only have the option of 'Parent: Child Business Unit' access, which allows you to see records from child business units, but there is not an option to see records from parent business units.

    If you wanted to do this I would recommend writing a plugin which on create or assign of Purchase Invoice, you share the Purchase Invoice with the default Teams of the Business Units that are a child of the owning users/teams Business Unit.

    Hope that helps

    Paul


    If my response helped you find your answer please show your thanks by taking the time to "Mark As Answer" and "Vote As Helpful".

    Twitter LinkedIn Facebook Blog Magnetism


    Saturday, August 10, 2013 4:39 AM
  • Hopefully, will try that soon

    Thank You so much Paul.


    Vinod P

    Saturday, August 10, 2013 7:36 AM
  • I wrote a proof of concept plugin if you want to take a look at that and just tweak it to your needs :)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using Microsoft.Crm.Sdk.Messages;
    
    namespace Tester.Plugins
    {
        /// <summary>
        /// On create or assign of a record, share the record with ALL child business units.
        /// This allows you to provide 'Child: Parent Business Units' access to any entities you want.
        /// 
        /// Plugin Registration Steps:
        /// create - post - sync
        /// update - post - sync - filtering: owningbusinessunit
        /// </summary>
        public class ShareWithChildBUs : IPlugin
        {
            private IOrganizationService _service;
    
            public void Execute(IServiceProvider serviceProvider)
            {
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
                IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                _service = factory.CreateOrganizationService(null); // Run in system context as users may have Assign but not Share
    
                if (!context.InputParameters.Contains("Target")) { return; }
                Entity target = context.InputParameters["Target"] as Entity;
                if (target == null) { return; }
    
                if (target.Contains("owningbusinessunit") && (EntityReference)target["owningbusinessunit"] != null)
                {
                    Share(target, context);
                }
            }
    
            private void Share(Entity target, IPluginExecutionContext context)
            {
                EntityReference targetRef = target.ToEntityReference();
                EntityReference owningBU = (EntityReference)target["owningbusinessunit"];
    
                if (context.MessageName.Equals("update", StringComparison.InvariantCultureIgnoreCase))
                {
                    // Unshare from all existing teams (if you don't want all existing teams removed on reassign you can comment this)
                    RevokeAccessFromTeams(targetRef);
                }
    
                // Share with ALL child business units
                ShareWithChildBusinessUnits(targetRef, owningBU.Id);
            }
    
            private void RevokeAccessFromTeams(EntityReference target)
            {
                // Get all the users/teams the record is already shared with
                var sharedWith = (RetrieveSharedPrincipalsAndAccessResponse)_service.Execute(new RetrieveSharedPrincipalsAndAccessRequest
                {
                    Target = target
                });
    
                if (sharedWith != null && sharedWith.PrincipalAccesses != null)
                {
                    sharedWith.PrincipalAccesses.ToList().ForEach(a =>
                    {
                        // Only unshare teams
                        if (a.Principal.LogicalName.Equals("team", StringComparison.InvariantCultureIgnoreCase))
                        {
                            // Revoke access from the team
                            _service.Execute(new RevokeAccessRequest
                            {
                                Target = target,
                                Revokee = a.Principal
                            });
                        }
                    });
                }
            }
    
            private void ShareWithChildBusinessUnits(EntityReference target, Guid businessUnitId)
            {
                // Get child teams and share with them
                List<Entity> childTeams = GetChildBusinessUnitTeams(businessUnitId);
                childTeams.ForEach(a =>
                {
                    Guid childBusinessUnitId = (Guid)((AliasedValue)a["bu.businessunitid"]).Value; // The child business unit
                    EntityReference teamReference = new EntityReference("team", a.Id); // The default team of the child business unit
    
                    // Grant access for the team
                    _service.Execute(new GrantAccessRequest
                    {
                        Target = target,
                        PrincipalAccess = new PrincipalAccess
                        {
                            // Only givesa Read and Write access (this can be modified as needed)
                            AccessMask = AccessRights.ReadAccess | AccessRights.WriteAccess,
                            Principal = teamReference
                        }
                    });
    
                    // Call this method for each child business unit to also share with all their children
                    // If you only want users to see one level up, comment this line
                    ShareWithChildBusinessUnits(target, childBusinessUnitId);
                });
            }
    
            private List<Entity> GetChildBusinessUnitTeams(Guid businessUnitId)
            {
                List<Entity> teams = new List<Entity>();
    
                EntityCollection collection = _service.RetrieveMultiple(new QueryExpression("team")
                {
                    Criteria =
                    {
                        Conditions =
                {
                    // We only want the default team, which contains all users of the business unit
                    new ConditionExpression("isdefault", ConditionOperator.Equal, true)
                }
                    },
                    LinkEntities =
            {
                new LinkEntity()
                {
                    LinkFromEntityName = "team",
                    LinkToEntityName = "businessunit",
                    LinkFromAttributeName = "businessunitid",
                    LinkToAttributeName = "businessunitid",
                    EntityAlias = "bu",
                    Columns = new ColumnSet("businessunitid"),
                    LinkCriteria =
                    {
                        Conditions =
                        {
                            new ConditionExpression("parentbusinessunitid", ConditionOperator.Equal, businessUnitId)
                        }
                    }
                }
            }
                });
    
                if (collection != null && collection.Entities.Count > 0)
                {
                    teams = collection.Entities.ToList();
                }
    
                return teams;
            }
        }
    }
    

    Hope that helps

    Paul


    If my response helped you find your answer please show your thanks by taking the time to "Mark As Answer" and "Vote As Helpful".

    Twitter LinkedIn Facebook Blog Magnetism

    Saturday, August 10, 2013 9:21 AM