Create an Alias. These are constructs like Foo.Bar. This is done when both operands are symbols that start with a capital letter.
Perform a call to a remote function. Here, the left-hand-side argument to . is the module, and the right-hand-side argument is the function name to call.
In your example, the second case happens. This is why you end up with the extra parentheses. For calling a zero-arity function, parentheses are optional (but many people like to add them to make it more explicit what is going on). Underwater, the elements of a struct are simply functions that are called on the secretly defined struct module, which will return the appropriate element from the underlying map.
So, Tl;Dr: You see p.location_id() because, as Elixir’s parser can infer from the ., location_id is a function.