Comment dessiner une société holding, des chaînes de propriété et calculer les parts de CFC

Dans la pratique juridique des avocats d'entreprise, relativement récemment (il y a plusieurs années), il est devenu nécessaire d'établir et de soumettre des notifications sur les sociétés étrangères contrôlées (CFC) en vertu de l'art. 25.13 du Code fiscal de la Fédération de Russie. L'essence de cette obligation est de rédiger et de soumettre un document qui reflétera toutes les connexions de la société dans la holding le long des chaînes de l'actuelle LLC (JSC) en Fédération de Russie au propriétaire-résident fiscal de la Fédération de Russie CFC. En termes simples, si l'offshore appartient à un Russe (résident fiscal de la Fédération de Russie) et l'offshore d'une LLC russe (même à travers la clôture des SARL intermédiaires) est supérieur à 25%, il y aura une notification. Le point culminant est qu'il est nécessaire de soumettre à toutes les SARL (JSC) dans lesquelles cette situation est observée et de soumettre à la fois des informations sur la propriété de plus de 25% et les modifications ultérieures de la part de propriété en temps opportun, sinon des amendes (100000 roubles pour chaque société de la chaîne - Art.129.6 Code fiscal de la Fédération de Russie).Étant donné que la holding (un ensemble d'entités juridiques) est un organisme vivant et que des changements constants dans les parts de propriété sont inévitables, il est nécessaire de surveiller en quelque sorte tout cela pour ne pas percevoir d'amendes. Comment simplifier le travail dans ce sens, l'automatiser, cet article est consacré. L'article sera également intéressant du point de vue de la présentation graphique des structures associées, par exemple, sociales. réseaux.







Dans cet article, nous ne nous attarderons pas sur les aspects juridiques des notifications soumises concernant un CFC, sur la participation à un CFC, nous examinerons l'aspect technique de la question.



Sans aucun doute, si la holding en question se présente comme de simples structures de type LLC-> KIK-> Russian, alors il n'est pas pratique de construire quelque chose ici avec l'implication d'une machine, c'est une autre affaire si la structure se ramifie, double et qu'il n'y a pas de nombre de ces imbrications.



Jetons un coup d'œil à plusieurs solutions graphiques existantes qui faciliteront votre travail.

Pour faciliter la visualisation, le notebook jupyter et l'environnement python seront utilisés.



Networkx



Cette solution est la plus ancienne de celles présentées et ne peut se vanter de son interactivité. Il y a le même article ancien sur ce paquet sur Habré.



Cependant, l'ancien ne veut pas dire mal, et cette option est l'une des plus réussies en termes de dessin et d'informatique.



Installez et importez le module via jupyter:



!pip install networkx
import networkx as nx


Nous importons également d'autres add. modules qui vous aideront à dessiner des formes:



from matplotlib import pyplot as plt
%matplotlib inline
plt.rcParams.update({
    'figure.figsize': (7.5, 7.5),
    'axes.spines.right': False,
    'axes.spines.left': False,
    'axes.spines.top': False,
    'axes.spines.bottom': False})


Construisons le premier réseau en utilisant networkx:



from pathlib import Path
data_dir = Path('.') / 'data'
# Read edge list
G = nx.read_edgelist('example.edgelist')
# Draw network
#pos = nx.spring_layout(G)
pos = nx.spectral_layout(G)
#pos = nx.planar_layout(G)
nx.draw_networkx(G, pos)
plt.gca().margins(0.15, 0.15)


Voici ce qui s'est passé:







comme vous pouvez le voir, Ivanov possède deux CFC, qui, à leur tour, possèdent des entités juridiques russes. par des personnes.



Analysons le code ci-dessus.



Nous avons importé le module et spécifié où nous allons lire les données sur le disque à partir de:



from pathlib import Path
data_dir = Path('.') / 'data'


Le répertoire actuel a été considéré comme «example.edgelist»:



G = nx.read_edgelist('example.edgelist')


* example.edgelist est un fichier texte brut comme celui-ci:



# source target
 1
 2
1 2
1 _
2 _


Les valeurs sont enregistrées par quelqu'un avec un espace entre elles.



Ensuite, nous avons déterminé à quoi ressemblera le réseau:



pos = nx.spectral_layout(G)


Si nous passons à pos = nx.spring_layout (G), alors cela prendra la forme:







Et cet arrangement, assez curieusement, est le plus approprié pour des structures plus grandes.



Enfin, nous avons dessiné le filet, marquant les tirets:



nx.draw_networkx(G, pos)
plt.gca().margins(0.15, 0.15)


Il est facile de sauvegarder une image:



plt.savefig('plot.png')


Comment dessiner un segment dans networkx



#
H = G.subgraph(['', '1', '_'])
plt.subplot(212) 
print(":") 
nx.draw_networkx(H)


Nous n'avons pas mis en







retrait ici, et les noms "à gauche": Networkx fonctionne avec les concepts de nœuds et de liens entre eux. Dans notre situation, les nœuds sont Ivanov, KIK1, KIK2, Romashka_OOO, Bucket_AO. Et les liens sont ce qui se trouve dans le fichier example.edgelist.



Vous pouvez voir les deux simplement en vous référant aux méthodes G.nodes et G.edges:







Graphique dirigé dans networkx (liste des bords dirigés)



Clarifions un peu le réseau construit, ajoutons des flèches:



# Read edge list
G = nx.read_edgelist(
    str('example.edgelist'),
    create_using=nx.DiGraph)
pos = nx.spectral_layout(G)
# Draw network
nx.draw_networkx(G, pos, arrowsize=20)
plt.gca().margins(0.15, 0.15)


De petits changements ont permis de brosser un tableau plus clair de qui possède qui:



Dans le code, comme vous pouvez le voir, les changements sont minimes.



L'étape suivante consiste à créer un graphique où la taille des packages de propriété sera visible.



Pour ce faire, vous devez vous familiariser avec le concept de poids (poids) est le troisième paramètre principal avec lequel networkx peut travailler. Pour l'inclure dans le travail, vous devez ajouter ces mêmes poids à un fichier texte, par exemple:



# source target
 1 100
 2 100
1 2 50
1 _ 100
2 _ 100


Reconstruisons maintenant le réseau en utilisant les poids et désignons-les sur le graphique:



# Read edge list
G = nx.read_weighted_edgelist(
    str('example2.edgelist'))
# Extract weights
weights = [d['weight'] for s, t, d in G.edges(data=True)]
nx.draw_networkx(G,pos)
labels = nx.get_edge_attributes(G,'weight')
nx.draw_networkx_edge_labels(G,pos,edge_labels=labels)
plt.gca().margins(0.15, 0.15)


* example2.edgelist est le fichier qui est généré ci-dessus avec des poids.



Prenons l'image suivante:







Qui possède qui et comment, networkx



Maintenant, en tant qu'avocats-programmeurs, nous devons comprendre dans quel ordre et dans quelle quantité Ivanov possède, par exemple, Bucket_AO, et s'il en est le propriétaire. Cela est nécessaire afin de déterminer le fait de détenir la propriété dans l'exploitation ramifiée et toutes les chaînes à la LLC cible (JSC), de sorte que plus tard, ces chaînes puissent être enregistrées dans la notification CFC.



Avec networkx, vous pouvez le faire comme suit:



list(nx.all_simple_paths(G,'', '_'))


Le premier argument est le nœud propriétaire, le second est le nœud vers lequel nous allons créer des chemins.



En utilisant cette méthode, vous pouvez voir que Bucket_AO d'Ivanov appartient aux chaînes suivantes:



[['', '1', '2', '_'], ['', '2', '_']]


Ceci est confirmé graphiquement.



Vous pouvez connaître la part de propriété en multipliant les poids entre les nœuds correspondants: 1 * 0,5 * 1 = 0,5, 1 * 1 = 1. Part de plus de 25%, la notification doit être soumise.



Dans le code, la multiplication se fait avec les béquilles suivantes (une méthode plus élégante n'a pas encore été trouvée):



x=0
b=0
c=[]
for i in list(nx.all_simple_paths(G,'', '_')):    
    for a in i:        
        if x>len(i)-2:
            pass                        
        else:            
            b=int(nx.bidirectional_dijkstra(G, i[x],i[x+1])[0])#                        
            x+=1
            c.append(b/100)              
print(c)
import numpy as np
print(np.prod(c))


x=0
b=0
c=[]
for i in list(nx.all_shortest_paths(G,'', '_')):
    for a in i:        
        if x>len(i)-2:
            pass                      
        else:            
            b=int(nx.bidirectional_dijkstra(G, i[x],i[x+1])[0])#                        
            x+=1
            c.append(b/100)              
print(c)
import numpy as np
print(np.prod(c))


Dans le premier cas, il affichera une fraction de 0,5, dans le second 1.



Quelles autres options de visualisation sont disponibles? Par exemple, Netwulf.



Netwulf



La documentation est ici .



Le réseau lui-même est interactif, c'est son principal avantage. Après avoir installé le package python, construisons le réseau:



import netwulf as nw
plt.figure(figsize=(200,200))
G = nx.read_weighted_edgelist(str('example2.edgelist'),create_using=nx.DiGraph)
pos = nx.spring_layout(G)
nw.visualize(G)


Après avoir exécuté le code, jupyter se fige, et dans une fenêtre de navigateur supplémentaire qui s'ouvre, vous pouvez voir le résultat:







sur le côté droit du panneau, vous pouvez voir les options dont le changement affecte le réseau construit en ligne.



L'inconvénient de ce package est qu'il n'est pas encore possible d'afficher les poids et les flèches entre les nœuds, mais les auteurs ont promis de l'affiner.



* pour revenir à jupyter, vous devez cliquer sur l'option "post to python":







Une autre bonne option pour une telle visualisation pour python est le jeune projet webweb.



Webweb



La documentation est ici .



Le réseau est construit de la même manière:



from webweb import Web
web = Web(title='kitchen_sink')

web.display.networkName = 'tree'
web.display.networkLayer = 2
web.display.colorBy = 'ring'
web.display.sizeBy = 'degree'
web.display.gravity = .3
web.display.charge = 30
web.display.linkLength = 15
web.display.colorPalette = 'Greens'
web.display.scaleLinkOpacity = False
web.display.scaleLinkWidth = True

from pathlib import Path
data_dir = Path('.') / 'data'
# Read edge list
G = nx.read_edgelist('example.edgelist',create_using=nx.DiGraph)
plt.figure(figsize=(200,200))
# Draw network
pos = nx.spring_layout(G)
Web(list(G.edges)).show()






Parmi les avantages évidents par rapport à netwulf: la possibilité de mettre en évidence les nœuds clés avec de la couleur, la recherche de texte pour les nœuds en surbrillance sur le réseau: En







résumé, nous pouvons dire que les descendants en développement de networkx - netwulf et webweb sont bons pour construire une image rapide de la structure d'une petite exploitation. Les deux modules ont un mode de gel pour figer les nœuds qui collent ensemble en raison de l'interactivité du graphique. Cependant, même en les utilisant, il n'est pas facile de travailler avec des structures à grande échelle, où le nombre de nœuds est supérieur à 200.



«Piédestal» du ministère des Finances, propriété croisée et en anneau



Tout serait très bien lors de la construction de telles structures, sinon pour une chose qui gâche toute l'image. Cela tient cependant au fait que les participations de la société se détiennent par l’intermédiaire d’autres entités juridiques. visages et cela s'appelle la propriété croisée ou en anneau.



Dans les images des lettres du ministère des Finances (par exemple, du 02.07.2013 -4-13 / 11912), cela ressemble à ceci.



Propriété croisée: en forme d'anneau







:







Voyons comment networkx définit les liens pour le schéma de propriété croisée de la participation de D dans B.



Créons une liste de diffusion avec des liens:



# source target
D B 45
B A 40
A B 55
E A 60


Après avoir construit un réseau avec des poids, vous pouvez voir que le retour entre A et B n'est pas reflété:







On peut voir si vous construisez un réseau sans poids, avec des flèches: qu'en est-







il des calculs? Quelle est la part cumulée de D dans B?



Tout semble transparent ici, 45%



Et networkx donne avec la liste de commandes (nx.all_simple_paths (G, 'D', 'B')):

[['D', 'B']]

Mais tout n'est pas si simple.



Le ministère des Finances indique que la part totale de D dans B est déterminée par la formule:







Et sera de 57,69%.



Que faire? networkx est impuissant?



Pas du tout, networkx révélera de telles situations, mais la formule de calcul sera différente, selon la «lettre de la loi».



Ce problème peut être partiellement résolu en ajoutant des entrées

AA

BB à la edgelist

De plus, avec la liste de commandes (nx.nodes_with_selfloops (G)), vous pouvez voir les nœuds avec une participation en eux-mêmes, mais cela n'est toujours pas pris en compte lors de la détermination des chemins de D à B.



Télécharger le cahier de jupyter - ici .



All Articles